Configurer la mise en veille des postes D.OS

Configurer la mise en veille des postes D.OS

Ce guide explique comment appliquer une politique de mise en veille identique sur tous vos postes W360 en mode D.OS, qu'il s'agisse de portables ou de postes fixes. La configuration est intégrée à votre poste master et s'applique automatiquement à chaque démarrage, sans aucune intervention sur les postes déployés.

En bref

PublicAdministrateurs et techniciens en charge du master D.OS
NiveauIntermédiaire (notions de base sur les stratégies de groupe Windows)
DuréeEnviron 30 minutes, validation comprise
OutilKit W360-Veille v1.1 (W360-Veille_v1.1.zip)
SystèmeWindows 10 Professionnel, Entreprise ou Éducation

Sommaire

  1. Comprendre le principe
  2. Avant de commencer
  3. Découvrir le kit
  4. Mise en place pas à pas
  5. Personnaliser la configuration
  6. Exemples prêts à l'emploi
  7. Vérifier que tout fonctionne
  8. Faire évoluer la politique
  9. Résoudre un problème
  10. Questions fréquentes
  11. Retirer la configuration
  12. Glossaire
  13. Aide-mémoire
  14. Annexe — Code source du kit

1. Comprendre le principe

Pourquoi la mise en veille est particulière en mode D.OS

En mode D.OS, le système des postes est protégé en lecture seule : à chaque redémarrage, le poste revient exactement à l'état de la version déployée. C'est ce qui garantit sa stabilité, mais cela a une conséquence directe : un réglage modifié pendant une session est perdu au redémarrage suivant.

Si vous réglez la mise en veille à la main sur un poste déployé, ce réglage disparaîtra donc au prochain démarrage. Pour qu'une politique de veille soit durable, elle doit faire partie de la version elle-même.

La solution retenue

Le kit W360-Veille repose sur trois éléments :

  1. Un fichier de configuration (W360-Veille.ini) dans lequel vous décrivez, en texte simple, le comportement souhaité.
  2. Un script (W360-Veille.ps1) qui lit ce fichier, reconnaît s'il tourne sur un portable ou un poste fixe, puis applique les réglages correspondants.
  3. Une stratégie de groupe locale qui lance ce script automatiquement à chaque démarrage du poste, avant l'ouverture de session.

Ces trois éléments sont installés une seule fois sur le poste master, puis intégrés à la version. Tous les postes déployés à partir de cette version appliquent la politique dès leur premier démarrage.

 Démarrage du poste
        │
        ▼
 Stratégie de groupe locale ── lance le script (compte SYSTEM)
        │
        ▼
 W360-Veille.ps1
        ├── lit W360-Veille.ini
        ├── détecte : portable ou poste fixe ?
        ├── applique les délais et les actions de veille
        └── écrit un compte rendu dans le journal

Bon à savoir — Le script s'exécute à chaque démarrage, et pas seulement une fois. C'est voulu : même si un utilisateur modifie les options d'alimentation pendant sa session, le poste retrouve la politique prévue au démarrage suivant.


2. Avant de commencer

Vérifiez les points suivants avant de vous lancer :

  • Vous disposez d'un poste master prêt pour une nouvelle version, avec un compte administrateur.
  • Le master tourne sous Windows 10 ou 11. L'éditeur de stratégie de groupe (gpedit.msc) n'existe pas en édition Famille.
  • Vous avez récupéré le kit W360-Veille_v1.1.zip.
  • Vous avez à disposition un portable et un poste fixe de test pour valider la version avant de la déployer.
  • Vous savez où conserver les journaux. Sur le volume système, ils sont effacés à chaque redémarrage ; pour garder un historique, prévoyez un volume persistant ou un partage réseau (voir § 5.6).

3. Découvrir le kit

FichierÀ quoi il sertFaut-il le modifier ?
Installer-Kit.cmdAssistant d'installation sur le masterNon
W360-Veille.iniFichier de configuration : c'est ici que vous décrivez votre politiqueOui
W360-Veille.ps1Script appliqué au démarrageNon
W360-Veille.cmdLanceur pour vos tests manuelsNon
LISEZMOI.mdDocumentation technique de référenceNon

Le contenu complet de chaque fichier est disponible en annexe : vous pouvez le consulter avant installation ou recréer le kit sans l'archive.

Important — W360-Veille.cmd sert uniquement aux tests manuels. Ne l'utilisez pas dans la stratégie de groupe : il marque une pause en fin d'exécution qui bloquerait le démarrage du poste.


4. Mise en place pas à pas

Toutes les étapes se déroulent sur le poste master.

Étape 1 — Installer le kit

Objectif : placer le kit dans un dossier stable et protégé.

  1. Décompressez W360-Veille_v1.1.zip dans un dossier de votre choix (par exemple sur le Bureau).
  2. Double-cliquez sur Installer-Kit.cmd et acceptez la demande d'élévation de droits.
  3. L'assistant enchaîne automatiquement cinq opérations :
    • copie du kit dans C:\ProgramData\Wisper\Veille ;
    • sécurisation du dossier ;
    • simulation de la configuration ;
    • copie des paramètres de la stratégie de groupe dans le presse-papiers ;
    • ouverture de l'éditeur de stratégie de groupe.

Résultat attendu : le dossier C:\ProgramData\Wisper\Veille contient les fichiers du kit et l'éditeur de stratégie de groupe est ouvert.

Pourquoi sécuriser le dossier ? — Le script s'exécute avec les droits les plus élevés du système (compte SYSTEM). Si un utilisateur standard pouvait le modifier, il pourrait s'octroyer ces droits au démarrage suivant. L'assistant limite donc l'écriture aux administrateurs ; les utilisateurs ne peuvent que lire.

Installation manuelle (sans l'assistant)

1. Créez le dossier C:\ProgramData\Wisper\Veille.
2. Copiez-y W360-Veille.ps1, W360-Veille.ini, W360-Veille.cmd et LISEZMOI.md.
3. Dans une invite de commandes ouverte en administrateur, sécurisez le dossier :

icacls "C:\ProgramData\Wisper\Veille" /inheritance:r /grant:r "*S-1-5-18:(OI)(CI)F" "*S-1-5-32-544:(OI)(CI)F" "*S-1-5-32-545:(OI)(CI)RX" /T

Étape 2 — Décrire votre politique de veille

Objectif : adapter la configuration à vos besoins.

  1. Ouvrez le Bloc-notes en tant qu'administrateur, puis ouvrez C:\ProgramData\Wisper\Veille\W360-Veille.ini.
  2. Ajustez les valeurs des sections [Portable] et [Fixe] (détail au § 5, modèles au § 6).
  3. Si vous souhaitez conserver un historique des journaux, renseignez DossierLog dans la section [Journal].
  4. Enregistrez le fichier en UTF-8 (Fichier > Enregistrer sous > Codage : UTF-8).

Résultat attendu : le fichier reflète votre politique. Les valeurs fournies par défaut conviennent à la plupart des usages et peuvent être conservées telles quelles pour un premier essai.

Étape 3 — Tester sans risque

Objectif : vérifier ce que le script va faire, sans rien modifier.

  1. Ouvrez une invite de commandes et lancez :
C:\ProgramData\Wisper\Veille\W360-Veille.cmd -Simulation
  1. Lisez le compte rendu affiché. Les lignes [SIMU] indiquent ce qui serait appliqué.

Résultat attendu : le type de poste détecté est correct, les valeurs correspondent à votre configuration et la dernière ligne indique 0 erreur(s). Si des lignes [AVERT] apparaissent, le script a corrigé ou ignoré une valeur : lisez le message, il indique la raison.

Étape 4 — Programmer le lancement au démarrage

Objectif : demander à Windows d'exécuter le script à chaque démarrage.

  1. Dans l'éditeur de stratégie de groupe (gpedit.msc), déroulez :
    Configuration ordinateur › Paramètres Windows › Scripts (démarrage/arrêt).
  2. Double-cliquez sur Démarrage.
  3. Restez sur l'onglet Scripts (et non Scripts PowerShell), puis cliquez sur Ajouter.
  4. Renseignez les deux champs :
ChampValeur à saisir
Nom du scriptC:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Paramètres du script-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "C:\ProgramData\Wisper\Veille\W360-Veille.ps1"
  1. Cliquez sur OK, puis de nouveau sur OK.

Astuce — Si vous avez utilisé l'assistant, la ligne de paramètres est déjà dans votre presse-papiers : un simple Ctrl + V suffit.

Résultat attendu : la ligne powershell.exe apparaît dans la liste des scripts de démarrage.

Étape 5 — Attendre le réseau (seulement si besoin)

Cette étape ne concerne que les installations où le fichier de configuration ou les journaux sont stockés sur un partage réseau. Sinon, passez directement à l'étape 6.

  1. Dans gpedit.msc, déroulez Configuration ordinateur › Modèles d'administration › Système › Ouverture de session.
  2. Activez « Toujours attendre le réseau lors du démarrage de l'ordinateur et de l'ouverture de session ».
  3. Revenez sur le script de démarrage (étape 4) et ajoutez à la fin des paramètres :
-AttenteConfig 60

Le script patientera jusqu'à 60 secondes que le fichier de configuration soit accessible.

À savoir — Au démarrage, aucun utilisateur n'est encore connecté : c'est le compte de l'ordinateur qui accède au partage. Le poste doit donc être membre d'un domaine et le partage doit autoriser le groupe « Ordinateurs du domaine ».

Étape 6 — Appliquer et contrôler sur le master

  1. Dans une invite de commandes administrateur, lancez gpupdate /force.
  2. Redémarrez le master.
  3. Effectuez les contrôles du § 7.

Résultat attendu : le journal contient une exécution datée du démarrage, lancée par le compte SYSTEM, sans erreur.

Étape 7 — Créer la version et valider

  1. Poursuivez votre procédure habituelle de création de version à partir du master.
  2. Déployez la version sur votre portable de test et votre poste fixe de test.
  3. Sur chacun, vérifiez dans le journal que le bon profil a été appliqué, puis testez concrètement : laissez le poste inactif, fermez le capot du portable, appuyez sur le bouton d'alimentation.
  4. Une fois la validation concluante, déployez la version sur le parc.

5. Personnaliser la configuration

5.1 Les règles d'écriture

Le fichier W360-Veille.ini se lit comme une liste de réglages, un par ligne :

[Section]
; Ceci est un commentaire, il est ignoré
Cle=Valeur
  • Les délais sont en minutes ; 0 signifie jamais.
  • Les interrupteurs prennent la valeur Oui ou Non.
  • Les majuscules et les accents sont indifférents : VeilleProlongée, veilleprolongee et VEILLEPROLONGEE sont équivalents.
  • Un réglage absent ou vide est laissé tel quel sur le poste : vous ne pilotez que ce que vous voulez.

5.2 Choisir le type de poste

Dans la section [General], la clé TypePoste détermine quel profil est appliqué :

ValeurComportement
Auto (recommandé)Le script reconnaît le matériel et applique [Portable] ou [Fixe]
PortableApplique toujours [Portable]
FixeApplique toujours [Fixe]

En mode Auto, le script s'appuie sur le type de châssis déclaré par le constructeur (portable, tablette, tour, mini-PC, tout-en-un…). Lorsque le châssis n'est pas identifiable, comme sur une machine virtuelle, il vérifie la présence d'une batterie. Le résultat de cette détection est toujours inscrit dans le journal.

5.3 Les délais

Chaque délai existe en deux versions : Secteur_ quand le poste est branché, Batterie_ quand il fonctionne sur batterie.

RéglageCe qu'il contrôle
Secteur_Ecran / Batterie_EcranExtinction de l'écran après N minutes d'inactivité
Secteur_Veille / Batterie_VeilleMise en veille après N minutes d'inactivité
Secteur_VeilleProlongee / Batterie_VeilleProlongeePassage en veille prolongée (nécessite l'hibernation)
Secteur_Disque / Batterie_DisqueArrêt du disque dur

Règle de cohérence — L'écran devrait s'éteindre avant la mise en veille. Par exemple : écran à 10 minutes, veille à 30 minutes.

5.4 Les actions

Ces réglages définissent ce qui se passe lorsque l'utilisateur agit sur le matériel.

RéglageDéclencheur
Secteur_Capot / Batterie_CapotFermeture du capot (portables uniquement)
Secteur_BoutonAlim / Batterie_BoutonAlimAppui bref sur le bouton d'alimentation
Secteur_BoutonVeille / Batterie_BoutonVeilleAppui sur la touche ou le bouton de veille
ValeurEffet
RienAucune action
VeilleMise en veille
VeilleProlongeeVeille prolongée (remplacée automatiquement par Veille si l'hibernation est désactivée)
ArretArrêt complet du poste
EteindreEcranExtinction de l'écran seul (bouton d'alimentation uniquement)

Poste fixe — Les réglages de capot sont ignorés. Si vous ne renseignez pas les valeurs Batterie_, le script reprend automatiquement les valeurs Secteur_, ce qui couvre le cas d'un poste branché sur onduleur.

5.5 Les options globales

RéglageRecommandation D.OSExplication
HibernationNonL'hibernation enregistre la mémoire sur le disque pour la restaurer au réveil, ce qui s'accorde mal avec un système en lecture seule
DemarrageRapideNonRepose sur l'hibernation ; le désactiver garantit un démarrage complet et propre à chaque allumage
VeilleHybrideNonRepose également sur l'hibernation
MotDePasseReveilOuiProtège la session si le poste est laissé sans surveillance
MinuteriesReveilNonEmpêche les réveils programmés intempestifs ; Importantes ne conserve que les réveils système critiques
PlanDedieOuiCrée un mode d'alimentation « W360 - Gestion veille » distinct des modes Windows, facile à identifier et à retirer

Attention — N'activez l'hibernation et les options qui en dépendent qu'après une validation spécifique sur un poste de test. Si vous les laissez désactivées et qu'un réglage y fait appel, le script le corrige automatiquement et le signale dans le journal.

5.6 Le journal

Chaque exécution est consignée dans un fichier par poste : Veille_<NOMDUPOSTE>.log.

RéglageDéfautRôle
DossierLog%ProgramData%\Wisper\Veille\LogsEmplacement du journal
TailleMaxKo512Taille au-delà de laquelle le journal est archivé
NombreArchives5Nombre d'archives conservées

Le principe du journal roulant : lorsque le journal atteint sa taille maximale, il est renommé en .1.log, l'archive .1 devient .2, et ainsi de suite. La plus ancienne est supprimée. L'espace occupé reste donc toujours limité.

Spécificité D.OS — Avec l'emplacement par défaut, situé sur le volume système, le journal est remis à zéro à chaque redémarrage : vous ne voyez que la dernière exécution, ce qui suffit pour un contrôle ponctuel. Pour conserver un historique, indiquez un volume persistant ou un partage réseau. Comme chaque poste écrit dans son propre fichier, un partage commun permet de centraliser les journaux de tout le parc.


6. Exemples prêts à l'emploi

Copiez la section qui correspond à votre usage dans W360-Veille.ini, puis ajustez les valeurs si nécessaire.

Salle de cours ou de formation (postes fixes)

Postes partagés, inactifs entre deux sessions : on économise l'énergie sans gêner les utilisateurs.

[Fixe]
Secteur_Ecran=10
Secteur_Veille=30
Secteur_VeilleProlongee=0
Secteur_Disque=20
Secteur_BoutonAlim=Arret
Secteur_BoutonVeille=Veille
VeilleHybride=Non
MinuteriesReveil=Non

Portables nomades

Autonomie privilégiée sur batterie, confort sur secteur, capot fermé = veille.

[Portable]
Secteur_Ecran=15
Secteur_Veille=45
Secteur_Capot=Veille
Secteur_BoutonAlim=Arret
Batterie_Ecran=3
Batterie_Veille=10
Batterie_Capot=Veille
Batterie_BoutonAlim=Veille
VeilleHybride=Non
MinuteriesReveil=Non

Poste d'accueil, de consultation ou d'affichage

Le poste doit rester disponible en permanence ; on évite aussi un arrêt accidentel par le bouton d'alimentation.

[Fixe]
Secteur_Ecran=0
Secteur_Veille=0
Secteur_Disque=0
Secteur_BoutonAlim=Rien
Secteur_BoutonVeille=Rien

Pour un écran d'affichage qui peut s'éteindre la nuit, remplacez Secteur_Ecran=0 par une valeur adaptée, par exemple 60.

Portables utilisés comme postes de bureau, capot fermé sur une station d'accueil

Sur secteur, fermer le capot ne doit pas interrompre le travail sur l'écran externe.

[Portable]
Secteur_Capot=Rien
Batterie_Capot=Veille

Économie d'énergie maximale

[Portable]
Secteur_Ecran=5
Secteur_Veille=15
Batterie_Ecran=2
Batterie_Veille=5

[Fixe]
Secteur_Ecran=5
Secteur_Veille=15

7. Vérifier que tout fonctionne

Les quatre contrôles

#ContrôleCommentRésultat attendu
1Le script s'est exécutéOuvrir le journal Veille_<NOMDUPOSTE>.logUne exécution datée du démarrage, contexte SYSTEM
2Aucune erreurDernière ligne du journal0 erreur(s)
3Le bon mode est actifpowercfg /getactivescheme« W360 - Gestion veille »
4La stratégie est en placegpresult /h %TEMP%\gpo.html, puis ouvrir le fichierLe script figure dans les scripts de démarrage de l'ordinateur

Vous pouvez aussi consulter les valeurs appliquées dans Panneau de configuration › Options d'alimentation › Modifier les paramètres du mode.

Lire le journal

2026-10-14 08:01:12 [INFO  ] W360-Veille v1.1.0 - Poste : PC-SALLE-042 - Contexte : SYSTEM (script de démarrage / tâche)
2026-10-14 08:01:13 [INFO  ] Type de poste détecté : Portable (châssis ou type système portable)
2026-10-14 08:01:13 [OK    ] Mise en veille (secteur) : 30 min
2026-10-14 08:01:13 [OK    ] Fermeture du capot (batterie) : Mettre en veille
2026-10-14 08:01:13 [AVERT ] Secteur_VeilleProlongee = 60 min mais l'hibernation est désactivée : forcé à 0 (jamais)
2026-10-14 08:01:14 [OK    ] Fin d'exécution : 0 erreur(s), 1 avertissement(s)
NiveauSignificationFaut-il agir ?
INFOInformation sur le déroulementNon
OKRéglage appliqué avec succèsNon
AVERTValeur corrigée ou ignorée par le scriptOui, corriger le .ini pour faire disparaître l'avertissement
ERREURRéglage non appliquéOui, voir le § 9
SIMUCe qui serait fait en mode simulationNon

8. Faire évoluer la politique

Deux organisations sont possibles, selon la fréquence à laquelle vous prévoyez de modifier la politique.

Configuration locale (par défaut)

Le fichier W360-Veille.ini fait partie de la version.

  • Avantage : fonctionnement totalement autonome, sans dépendance au réseau.
  • Pour modifier : éditer le .ini sur le master, tester avec -Simulation, puis créer une nouvelle version.

Configuration centralisée sur le réseau

Le fichier W360-Veille.ini est placé sur un partage réseau et lu par tous les postes au démarrage.

  • Avantage : une modification du fichier s'applique à tout le parc au redémarrage suivant, sans nouvelle version.
  • Mise en place : ajouter aux paramètres du script de démarrage :
-FichierConfig "\\serveur\partage\W360-Veille.ini" -AttenteConfig 60

puis activer l'attente du réseau (étape 5).

Sécurité — Le contenu de ce fichier pilote un script exécuté avec les droits SYSTEM sur tous vos postes. Réservez les droits d'écriture du partage aux seuls administrateurs.


9. Résoudre un problème

SymptômeCause probableSolution
Aucun journal après le redémarrageLe script ne s'est pas lancéVérifier avec gpresult que le script est déclaré ; contrôler le chemin et les guillemets dans les paramètres ; vérifier que l'onglet utilisé est bien Scripts
Journal introuvable à l'emplacement prévuDossier inaccessible en écritureConsulter C:\Windows\Temp\W360_Veille, où le script se replie automatiquement
Le journal ne contient qu'une seule exécutionJournal sur le volume système protégéComportement normal en D.OS ; voir § 5.6 pour conserver un historique
« Fichier de configuration introuvable »Partage réseau pas encore disponible au démarrageActiver l'attente du réseau et -AttenteConfig ; vérifier les droits du compte ordinateur sur le partage
Le mauvais profil est appliquéChâssis mal déclaré par le constructeurLire la ligne « Détection » du journal ; forcer le type avec -TypePoste Portable ou -TypePoste Fixe dans les paramètres du script
Les réglages ne correspondent pas au fichierUne stratégie de domaine écrase la configurationVérifier les paramètres de Gestion de l'alimentation dans les GPO de domaine, prioritaires sur la stratégie locale
La veille ne se déclenche pasUne application ou un périphérique maintient le poste éveilléExécuter powercfg /requests pendant l'inactivité pour identifier le responsable
Erreur sur EteindreEcranOption absente de certaines versions de Windows 10Utiliser Veille à la place
Accents illisibles dans le nom du modeFichier .ini mal encodéRéenregistrer le fichier en UTF-8
gpedit.msc introuvableWindows 10 FamilleÉdition non prise en charge

Commandes utiles

CommandeUsage
powercfg /listLister les modes d'alimentation
powercfg /getactiveschemeAfficher le mode actif
powercfg /qAfficher tous les réglages du mode actif
powercfg /aAfficher les états de veille pris en charge par le matériel
powercfg /requestsIdentifier ce qui empêche la mise en veille
gpresult /h rapport.htmlGénérer le rapport des stratégies appliquées

10. Questions fréquentes

Les utilisateurs peuvent-ils modifier la mise en veille ?
Oui, pendant leur session, s'ils disposent des droits nécessaires. Mais leurs modifications disparaissent au redémarrage : le poste revient à la version et le script réapplique la politique.

Le script ralentit-il le démarrage ?
Non, de façon imperceptible. Son exécution dure quelques secondes et a lieu avant l'ouverture de session. Seule l'option d'attente du réseau, si vous l'activez, peut allonger légèrement le démarrage.

Puis-je avoir des réglages différents d'une salle ou d'un site à l'autre ?
Oui. Avec une configuration centralisée, chaque groupe de postes peut pointer vers son propre fichier grâce au paramètre -FichierConfig. Avec une configuration locale, il faut une version par politique.

Le script fonctionne-t-il sur une machine virtuelle ?
Oui. Le châssis d'une machine virtuelle n'étant généralement pas identifiable, le script la considère comme un poste fixe, sauf si une batterie virtuelle est présente. Vous pouvez aussi forcer le type.

Que se passe-t-il si je laisse un réglage vide ?
Le réglage correspondant n'est pas modifié sur le poste : c'est la valeur présente dans la version qui s'applique.

Comment tester une modification sans risque ?
Lancez W360-Veille.cmd -Simulation sur le master. Rien n'est modifié, mais le compte rendu indique précisément ce qui serait appliqué.

Puis-je utiliser une tâche planifiée plutôt qu'une stratégie de groupe ?
Oui, avec W360-Veille.cmd -InstallerTache. N'utilisez cependant pas les deux méthodes en même temps : le script s'exécuterait deux fois à chaque démarrage.


11. Retirer la configuration

Toutes les opérations se font sur le master, avant de créer une nouvelle version.

  1. Dans gpedit.msc, déroulez Configuration ordinateur › Paramètres Windows › Scripts (démarrage/arrêt) › Démarrage, sélectionnez la ligne powershell.exe et cliquez sur Supprimer.
  2. Dans une invite de commandes administrateur, restaurez le mode d'alimentation Windows :
C:\ProgramData\Wisper\Veille\W360-Veille.cmd -Restaurer
  1. Lancez gpupdate /force.
  2. Si vous le souhaitez, supprimez le dossier C:\ProgramData\Wisper\Veille.
  3. Créez la nouvelle version.

La restauration réactive le mode Windows « Utilisation normale » et supprime le mode « W360 - Gestion veille ». Les réglages d'hibernation et de démarrage rapide ne sont pas modifiés.


12. Glossaire

TermeDéfinition
D.OSMode de fonctionnement W360 dans lequel le système des postes est protégé en lecture seule et revient à l'état de la version à chaque redémarrage
Poste masterPoste de référence sur lequel est préparée la configuration avant la création d'une version
VersionImage du système produite à partir du master et déployée sur les postes
Stratégie de groupe locale (GPO locale)Ensemble de règles Windows propres à un poste, modifiables avec gpedit.msc
Script de démarrageProgramme lancé automatiquement par Windows au démarrage, avant l'ouverture de session
Compte SYSTEMCompte interne de Windows disposant des droits les plus élevés sur le poste
Mode d'alimentationEnsemble de réglages d'énergie Windows (délais, actions des boutons…)
VeilleÉtat de faible consommation dont le poste sort en quelques secondes ; la session reste en mémoire
Veille prolongée (hibernation)La session est enregistrée sur le disque et le poste s'éteint complètement
Journal roulantFichier de compte rendu archivé automatiquement lorsqu'il atteint sa taille maximale

13. Aide-mémoire

Je veux…Je fais…
Installer le kit sur le masterDouble-clic sur Installer-Kit.cmd
Modifier la politiqueÉditer C:\ProgramData\Wisper\Veille\W360-Veille.ini en administrateur
Tester sans rien modifierW360-Veille.cmd -Simulation
Appliquer immédiatement à la mainDouble-clic sur W360-Veille.cmd
Forcer le profilAjouter -TypePoste Portable ou -TypePoste Fixe
Utiliser un fichier réseauAjouter -FichierConfig "\\serveur\partage\W360-Veille.ini" -AttenteConfig 60
Vérifier le mode actifpowercfg /getactivescheme
Trouver ce qui bloque la veillepowercfg /requests
Tout retirerSupprimer le script dans gpedit.msc, puis W360-Veille.cmd -Restaurer

Paramètres du script de démarrage :

Nom du script :  C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Paramètres :     -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "C:\ProgramData\Wisper\Veille\W360-Veille.ps1"

14. Annexe — Code source du kit

Cette annexe reproduit l'intégralité des fichiers du kit W360-Veille v1.1. Elle vous permet de vérifier précisément ce qui sera exécuté sur vos postes, ou de recréer le kit si vous ne disposez pas de l'archive.

14.1 Recréer le kit à partir de cette page

  1. Créez un dossier, par exemple W360-Veille sur le Bureau du master.
  2. Pour chaque fichier ci-dessous, ouvrez le Bloc-notes, copiez-collez le contenu du bloc, puis enregistrez sous le nom indiqué en respectant le codage précisé.
  3. Dans la boîte « Enregistrer sous », choisissez Type : Tous les fichiers (*.*), sinon le Bloc-notes ajoute l'extension .txt.
  4. Poursuivez avec l'étape 1 de la mise en place.
FichierCodage à l'enregistrementPourquoi
W360-Veille.ps1UTF-8 avec BOMIndispensable : sans BOM, Windows PowerShell 5.1 interprète mal les caractères accentués du script
W360-Veille.iniUTF-8 (avec ou sans BOM)Les deux sont acceptés par le script
W360-Veille.cmdANSI ou UTF-8 sans BOMLe fichier ne contient volontairement aucun accent
Installer-Kit.cmdANSI ou UTF-8 sans BOMIdem

Astuce — Dans le Bloc-notes de Windows 10 (version 1903 et suivantes), le choix « UTF-8 avec BOM » se trouve dans la liste Codage de la boîte « Enregistrer sous ». Sur les versions plus anciennes, l'option « UTF-8 » enregistre déjà avec BOM.

Vérification — Après création, ouvrez une console PowerShell dans le dossier et lancez Get-Help .\W360-Veille.ps1 -Full. Si l'aide s'affiche avec des accents corrects, le fichier est bien encodé.

14.2 W360-Veille.ini — Configuration

Le seul fichier à adapter. Les valeurs ci-dessous sont les valeurs par défaut.

; =====================================================================
;  W360-Veille - Configuration de la mise en veille (postes D.OS / RO)
; =====================================================================
;  - Une ligne par paramètre : Cle=Valeur
;  - Les lignes commençant par ; ou # sont des commentaires
;  - Délais en MINUTES, 0 = jamais
;  - Actions possibles :
;      Rien | Veille | VeilleProlongee | Arret
;      EteindreEcran (uniquement pour BoutonAlim)
;  - Oui / Non pour les interrupteurs
;  - Un paramètre absent ou vide est laissé inchangé sur le poste
; =====================================================================

[General]
; Auto = détection automatique | Portable | Fixe
TypePoste=Auto

; Oui = crée / met à jour un mode d'alimentation dédié (recommandé)
; Non = modifie le mode d'alimentation actuellement actif
PlanDedie=Oui
NomPlan=W360 - Gestion veille

; Hibernation globale (fichier hiberfil.sys). Requise pour VeilleProlongee,
; la veille hybride et le démarrage rapide. Déconseillée sur poste en lecture seule.
Hibernation=Non

; Démarrage rapide Windows (nécessite Hibernation=Oui)
DemarrageRapide=Non

; Demander le mot de passe à la sortie de veille
MotDePasseReveil=Oui

; Oui = n'applique rien, journalise seulement ce qui serait fait
Simulation=Non


[Journal]
; Dossier des logs. Sur un poste en lecture seule, pointer vers un volume
; PERSISTANT (ou un partage réseau), sinon les logs disparaissent au redémarrage.
; Les variables d'environnement sont acceptées : %COMPUTERNAME%, %ProgramData%...
DossierLog=%ProgramData%\Wisper\Veille\Logs

; Taille maximale du log courant avant rotation (en Ko)
TailleMaxKo=512

; Nombre d'archives conservées (Veille_POSTE.1.log ... .N.log)
NombreArchives=5


[Portable]
; --- Sur secteur ---
Secteur_Ecran=10
Secteur_Veille=30
Secteur_VeilleProlongee=0
Secteur_Disque=20
Secteur_Capot=Veille
Secteur_BoutonAlim=Arret
Secteur_BoutonVeille=Veille

; --- Sur batterie ---
Batterie_Ecran=5
Batterie_Veille=15
Batterie_VeilleProlongee=0
Batterie_Disque=10
Batterie_Capot=Veille
Batterie_BoutonAlim=Arret
Batterie_BoutonVeille=Veille

; --- Options ---
; Veille hybride (nécessite Hibernation=Oui)
VeilleHybride=Non
; Minuteries de réveil : Oui | Non | Importantes
MinuteriesReveil=Non


[Fixe]
; Un poste fixe n'a pas de capot : les paramètres Capot sont ignorés.
; Les valeurs Batterie_* absentes reprennent les valeurs Secteur_* (cas onduleur).
Secteur_Ecran=15
Secteur_Veille=60
Secteur_VeilleProlongee=0
Secteur_Disque=30
Secteur_BoutonAlim=Arret
Secteur_BoutonVeille=Veille

VeilleHybride=Non
MinuteriesReveil=Non

14.3 W360-Veille.ps1 — Script principal

Script lancé au démarrage par la stratégie de groupe locale. Il ne nécessite aucune modification : tout se règle dans le fichier .ini.

Ce que fait le script, dans l'ordre :

  1. lit le fichier de configuration (en patientant si demandé avec -AttenteConfig) ;
  2. prépare le journal et l'archive si sa taille maximale est atteinte ;
  3. vérifie les droits administrateur ;
  4. détermine le type de poste, détecté ou forcé ;
  5. règle l'hibernation et le démarrage rapide ;
  6. crée ou met à jour le mode d'alimentation « W360 - Gestion veille » ;
  7. applique les délais, les actions et les options du profil, sur secteur puis sur batterie ;
  8. active le mode, inscrit les états de veille du matériel puis un bilan dans le journal.
#Requires -Version 5.1
<#
.SYNOPSIS
    Configuration de la mise en veille des postes W360 en mode D.OS (lecture seule).

.DESCRIPTION
    Lit le fichier W360-Veille.ini, détecte (ou force) le type de poste
    (Portable / Fixe) et applique les délais et actions de veille correspondants
    via powercfg. Toutes les opérations sont tracées dans un journal roulant.

.PARAMETER FichierConfig
    Chemin du fichier de configuration. Par défaut : W360-Veille.ini à côté du script.

.PARAMETER TypePoste
    Force le type de poste (Auto, Portable, Fixe). Prioritaire sur le fichier .ini.

.PARAMETER Simulation
    N'applique rien : journalise uniquement ce qui serait fait.

.PARAMETER InstallerTache
    Crée une tâche planifiée (compte SYSTEM, au démarrage) qui relance ce script,
    puis applique la configuration.

.PARAMETER SupprimerTache
    Supprime la tâche planifiée.

.PARAMETER Restaurer
    Réactive le mode Windows "Utilisation normale" et supprime le mode dédié.

.PARAMETER AttenteConfig
    Délai maximal (secondes, 0 à 600) d'attente du fichier de configuration.
    Utile au démarrage si le .ini est sur un partage réseau pas encore disponible.

.EXAMPLE
    .\W360-Veille.ps1
.EXAMPLE
    .\W360-Veille.ps1 -TypePoste Portable -Simulation
.EXAMPLE
    powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "C:\ProgramData\Wisper\Veille\W360-Veille.ps1"
    (ligne type pour un script de démarrage en GPO locale)

.NOTES
    Version 1.1.0
    Codes retour : 0 = OK | 1 = erreur(s) d'application | 2 = configuration | 3 = droits
#>
[CmdletBinding()]
param(
    [string]$FichierConfig = (Join-Path -Path $PSScriptRoot -ChildPath 'W360-Veille.ini'),
    [ValidateSet('Auto', 'Portable', 'Fixe')]
    [string]$TypePoste,
    [switch]$Simulation,
    [switch]$InstallerTache,
    [switch]$SupprimerTache,
    [switch]$Restaurer,
    [ValidateRange(0, 600)]
    [int]$AttenteConfig = 0
)

Set-StrictMode -Version 2.0
$ErrorActionPreference = 'Stop'

# ---------------------------------------------------------------------------
#  Constantes
# ---------------------------------------------------------------------------
$Script:Version        = '1.1.0'
$Script:NomTache       = 'W360 - Configuration veille'
$Script:GuidPlan       = 'd05e1e3a-7c41-4b2e-9f6a-3605e0a1c360'   # GUID fixe => script idempotent
$Script:GuidEquilibre  = '381b4222-f694-41f0-9685-ff5bb260df2e'   # "Utilisation normale"
$Script:RegexGuid      = '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'
$Script:FichierLog     = $null
$Script:NbErreurs      = 0
$Script:NbAvert        = 0
$Script:CodeSortie     = 0
$Script:ModeSimulation = [bool]$Simulation

# Valeurs powercfg des actions (LIDACTION / PBUTTONACTION / SBUTTONACTION)
$Script:CodesAction = @{
    'rien' = 0; 'nerienfaire' = 0
    'veille' = 1; 'miseenveille' = 1
    'veilleprolongee' = 2; 'hibernation' = 2
    'arret' = 3; 'eteindre' = 3
    'eteindreecran' = 4
}
$Script:LibellesAction = @('Ne rien faire', 'Mettre en veille', 'Veille prolongée', 'Arrêter', "Éteindre l'écran")

# ---------------------------------------------------------------------------
#  Journalisation (log roulant)
# ---------------------------------------------------------------------------
function Write-Log {
    param(
        [string]$Message,
        [ValidateSet('INFO', 'OK', 'AVERT', 'ERREUR', 'SIMU')]
        [string]$Niveau = 'INFO'
    )
    $ligne = '{0} [{1,-6}] {2}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Niveau, $Message
    if ($Niveau -eq 'AVERT')  { $Script:NbAvert++ }
    if ($Niveau -eq 'ERREUR') { $Script:NbErreurs++ }
    $couleurs = @{ INFO = 'Gray'; OK = 'Green'; AVERT = 'Yellow'; ERREUR = 'Red'; SIMU = 'Cyan' }
    Write-Host $ligne -ForegroundColor $couleurs[$Niveau]
    if ($Script:FichierLog) {
        try { Add-Content -LiteralPath $Script:FichierLog -Value $ligne -Encoding UTF8 } catch { }
    }
}

function Initialize-Journal {
    param([string]$Dossier, [int]$TailleMaxKo, [int]$NbArchives)

    $repli = $false
    try {
        if (-not (Test-Path -LiteralPath $Dossier)) {
            $null = New-Item -ItemType Directory -Path $Dossier -Force
        }
        $test = Join-Path $Dossier '.test_ecriture'
        Set-Content -LiteralPath $test -Value 'ok'
        Remove-Item -LiteralPath $test -Force
    }
    catch {
        $repli = $true
        $demande = $Dossier
        $Dossier = Join-Path ([IO.Path]::GetTempPath()) 'W360_Veille'
        $null = New-Item -ItemType Directory -Path $Dossier -Force
    }

    $base = Join-Path $Dossier ("Veille_{0}" -f $env:COMPUTERNAME)
    $Script:FichierLog = "$base.log"

    # Rotation : Veille_POSTE.log -> .1.log -> .2.log ... -> supprimé au-delà de NbArchives
    if ((Test-Path -LiteralPath $Script:FichierLog) -and
        ((Get-Item -LiteralPath $Script:FichierLog).Length -gt ($TailleMaxKo * 1KB))) {
        if ($NbArchives -lt 1) {
            Remove-Item -LiteralPath $Script:FichierLog -Force
        }
        else {
            $plusAncienne = "$base.$NbArchives.log"
            if (Test-Path -LiteralPath $plusAncienne) { Remove-Item -LiteralPath $plusAncienne -Force }
            for ($i = $NbArchives - 1; $i -ge 1; $i--) {
                $source = "$base.$i.log"
                if (Test-Path -LiteralPath $source) { Move-Item -LiteralPath $source -Destination "$base.$($i + 1).log" -Force }
            }
            Move-Item -LiteralPath $Script:FichierLog -Destination "$base.1.log" -Force
        }
    }

    if ($repli) { Write-Log "Dossier de log '$demande' inaccessible en écriture : repli sur '$Dossier'" 'AVERT' }
}

# ---------------------------------------------------------------------------
#  Lecture de la configuration
# ---------------------------------------------------------------------------
function Read-Ini {
    param([string]$Chemin)
    $ini = @{}
    $section = 'General'
    foreach ($brute in Get-Content -LiteralPath $Chemin -Encoding UTF8) {
        $l = $brute.Trim()
        if ($l -eq '' -or $l.StartsWith(';') -or $l.StartsWith('#')) { continue }
        if ($l -match '^\[(.+)\]$') {
            $section = $Matches[1].Trim()
            if (-not $ini.ContainsKey($section)) { $ini[$section] = @{} }
            continue
        }
        if ($l -match '^([^=]+)=(.*)$') {
            $cle = $Matches[1].Trim()
            $val = ($Matches[2] -replace '\s+[;#].*$', '').Trim()
            if (-not $ini.ContainsKey($section)) { $ini[$section] = @{} }
            $ini[$section][$cle] = $val
        }
    }
    return $ini
}

function Get-Section {
    param([hashtable]$Ini, [string]$Nom)
    if ($Ini.ContainsKey($Nom)) { return $Ini[$Nom] }
    return @{}
}

function Get-Valeur {
    param([hashtable]$Section, [string]$Cle, $Defaut)
    if ($Section.ContainsKey($Cle) -and "$($Section[$Cle])" -ne '') { return $Section[$Cle] }
    return $Defaut
}

# Batterie_* absent sur un poste fixe => reprend Secteur_*
function Get-ValeurProfil {
    param([hashtable]$Profil, [string]$Cle, [string]$Type)
    if ($Profil.ContainsKey($Cle) -and "$($Profil[$Cle])" -ne '') { return $Profil[$Cle] }
    if ($Type -eq 'Fixe' -and $Cle -like 'Batterie_*') {
        $alt = $Cle -replace '^Batterie_', 'Secteur_'
        if ($Profil.ContainsKey($alt) -and "$($Profil[$alt])" -ne '') { return $Profil[$alt] }
    }
    return $null
}

# Normalise un texte : minuscules, sans accents, sans espaces/tirets
function ConvertTo-Cle {
    param([string]$Texte)
    $decompose = "$Texte".Normalize([Text.NormalizationForm]::FormD)
    $sb = New-Object System.Text.StringBuilder
    foreach ($c in $decompose.ToCharArray()) {
        if ([Globalization.CharUnicodeInfo]::GetUnicodeCategory($c) -ne [Globalization.UnicodeCategory]::NonSpacingMark) {
            $null = $sb.Append($c)
        }
    }
    return ($sb.ToString().ToLowerInvariant() -replace '[\s_\-]', '')
}

function ConvertTo-Booleen {
    param([string]$Valeur)
    return @('oui', 'o', 'yes', 'y', '1', 'true', 'vrai', 'actif') -contains (ConvertTo-Cle $Valeur)
}

function ConvertTo-Entier {
    param($Valeur, [int]$Defaut)
    $n = 0
    if ([int]::TryParse("$Valeur", [ref]$n) -and $n -ge 0) { return $n }
    return $Defaut
}

function ConvertTo-Minutes {
    param($Valeur, [string]$Nom)
    $n = 0
    if ([int]::TryParse("$Valeur", [ref]$n) -and $n -ge 0) { return $n }
    Write-Log "$Nom : '$Valeur' n'est pas un nombre de minutes valide, paramètre ignoré" 'AVERT'
    return $null
}

function Format-Minutes {
    param([int]$Minutes)
    if ($Minutes -eq 0) { return 'Jamais' }
    return "$Minutes min"
}

function Resolve-Action {
    param([string]$Valeur, [string]$Nom, [bool]$HiberOK, [bool]$AutoriserEcran)
    $cle = ConvertTo-Cle $Valeur
    if (-not $Script:CodesAction.ContainsKey($cle)) {
        Write-Log "$Nom : action '$Valeur' inconnue (Rien|Veille|VeilleProlongee|Arret|EteindreEcran), paramètre ignoré" 'AVERT'
        return $null
    }
    $code = $Script:CodesAction[$cle]
    if ($code -eq 4 -and -not $AutoriserEcran) {
        Write-Log "$Nom : 'EteindreEcran' n'est valable que pour le bouton d'alimentation, remplacé par 'Veille'" 'AVERT'
        $code = 1
    }
    if ($code -eq 2 -and -not $HiberOK) {
        Write-Log "$Nom : veille prolongée demandée mais l'hibernation est désactivée, remplacé par 'Veille'" 'AVERT'
        $code = 1
    }
    return $code
}

# ---------------------------------------------------------------------------
#  Système
# ---------------------------------------------------------------------------
function Test-Admin {
    $id = [Security.Principal.WindowsIdentity]::GetCurrent()
    return ([Security.Principal.WindowsPrincipal]$id).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Get-TypePosteDetecte {
    $portables = 8, 9, 10, 11, 12, 14, 18, 21, 30, 31, 32
    $fixes     = 3, 4, 5, 6, 7, 13, 15, 16, 24, 35, 36
    $chassis = @(); $pcType = 0; $batterie = $false

    try { $chassis = @(Get-CimInstance -ClassName Win32_SystemEnclosure | ForEach-Object { $_.ChassisTypes }) } catch { }
    try { $pcType = [int](Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -First 1).PCSystemType } catch { }
    try { $batterie = @(Get-CimInstance -ClassName Win32_Battery).Count -gt 0 } catch { }

    Write-Log ("Détection : châssis = [{0}] ; PCSystemType = {1} ; batterie = {2}" -f ($chassis -join ','), $pcType, $(if ($batterie) { 'oui' } else { 'non' }))

    if (@($chassis | Where-Object { $portables -contains $_ }).Count -gt 0 -or $pcType -eq 2) {
        $type = 'Portable'; $raison = 'châssis ou type système portable'
    }
    elseif (@($chassis | Where-Object { $fixes -contains $_ }).Count -gt 0) {
        $type = 'Fixe'; $raison = 'châssis de poste fixe'
    }
    elseif ($batterie) {
        $type = 'Portable'; $raison = 'châssis indéterminé, batterie détectée'
    }
    else {
        $type = 'Fixe'; $raison = 'châssis indéterminé, aucune batterie'
    }
    Write-Log "Type de poste détecté : $type ($raison)"
    return $type
}

function Invoke-Powercfg {
    param([string[]]$Arguments, [string]$Description)
    if ($Script:ModeSimulation) {
        Write-Log "$Description   [powercfg $($Arguments -join ' ')]" 'SIMU'
        return $true
    }
    $ErrorActionPreference = 'Continue'   # évite qu'une sortie stderr native ne lève une exception
    $sortie = & powercfg.exe @Arguments 2>&1
    if ($LASTEXITCODE -eq 0) {
        Write-Log $Description 'OK'
        return $true
    }
    $msg = (@($sortie) | ForEach-Object { "$_".Trim() } | Where-Object { $_ }) -join ' '
    Write-Log "$Description : ÉCHEC (code $LASTEXITCODE) $msg" 'ERREUR'
    return $false
}

function Set-Parametre {
    param(
        [string]$Guid,
        [ValidateSet('AC', 'DC')][string]$Mode,
        [string]$Sous, [string]$Param, [int]$Valeur,
        [string]$Libelle, [string]$Affichage
    )
    $verbe  = if ($Mode -eq 'AC') { '/setacvalueindex' } else { '/setdcvalueindex' }
    $source = if ($Mode -eq 'AC') { 'secteur' } else { 'batterie' }
    $null = Invoke-Powercfg -Arguments @($verbe, $Guid, $Sous, $Param, "$Valeur") `
                            -Description ("{0} ({1}) : {2}" -f $Libelle, $source, $Affichage)
}

function Get-PlanCible {
    param([bool]$Dedie, [string]$Nom)

    if (-not $Dedie) {
        $actif = (& powercfg.exe /getactivescheme) -join ' '
        if ($actif -match $Script:RegexGuid) {
            Write-Log "Modification du mode actif : $($actif.Trim())"
            return $Matches[0]
        }
        Write-Log "Impossible de lire le mode d'alimentation actif" 'ERREUR'
        return $null
    }

    $existe = [bool]((& powercfg.exe /list) -match $Script:GuidPlan)
    if ($existe) {
        Write-Log "Mode dédié déjà présent ($($Script:GuidPlan)) : mise à jour"
    }
    else {
        $ok = Invoke-Powercfg -Arguments @('/duplicatescheme', $Script:GuidEquilibre, $Script:GuidPlan) `
                              -Description "Création du mode dédié à partir de 'Utilisation normale'"
        if (-not $ok) {
            $actif = (& powercfg.exe /getactivescheme) -join ' '
            if ($actif -match $Script:RegexGuid) {
                $ok = Invoke-Powercfg -Arguments @('/duplicatescheme', $Matches[0], $Script:GuidPlan) `
                                      -Description 'Création du mode dédié à partir du mode actif (repli)'
            }
        }
        if (-not $ok) { return $null }
    }
    $null = Invoke-Powercfg -Arguments @('/changename', $Script:GuidPlan, $Nom, 'Mode géré par W360-Veille.ps1') `
                            -Description "Nom du mode : $Nom"
    return $Script:GuidPlan
}

function Set-DemarrageRapide {
    param([bool]$Actif)
    $chemin  = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power'
    $valeur  = [int]$Actif
    $libelle = "Démarrage rapide : $(if ($Actif) { 'activé' } else { 'désactivé' })"
    if ($Script:ModeSimulation) { Write-Log "$libelle   [HiberbootEnabled=$valeur]" 'SIMU'; return }
    try {
        Set-ItemProperty -Path $chemin -Name 'HiberbootEnabled' -Value $valeur -Type DWord -Force
        Write-Log $libelle 'OK'
    }
    catch { Write-Log "$libelle : ÉCHEC ($($_.Exception.Message))" 'ERREUR' }
}

function Set-ProfilVeille {
    param([string]$Guid, [hashtable]$Profil, [string]$Type, [bool]$HiberOK)

    $delais = @(
        @{ Cle = 'Ecran';           Sous = 'SUB_VIDEO'; Param = 'VIDEOIDLE';     Libelle = "Extinction de l'écran" },
        @{ Cle = 'Veille';          Sous = 'SUB_SLEEP'; Param = 'STANDBYIDLE';   Libelle = 'Mise en veille' },
        @{ Cle = 'VeilleProlongee'; Sous = 'SUB_SLEEP'; Param = 'HIBERNATEIDLE'; Libelle = 'Veille prolongée' },
        @{ Cle = 'Disque';          Sous = 'SUB_DISK';  Param = 'DISKIDLE';      Libelle = 'Arrêt du disque' }
    )
    $actions = @(
        @{ Cle = 'Capot';        Param = 'LIDACTION';     Libelle = 'Fermeture du capot';       Ecran = $false },
        @{ Cle = 'BoutonAlim';   Param = 'PBUTTONACTION'; Libelle = "Bouton d'alimentation";    Ecran = $true },
        @{ Cle = 'BoutonVeille'; Param = 'SBUTTONACTION'; Libelle = 'Bouton de mise en veille'; Ecran = $false }
    )

    if ($Type -eq 'Fixe') { Write-Log 'Poste fixe : paramètres de capot ignorés, valeurs batterie = valeurs secteur si absentes' }

    foreach ($mode in 'AC', 'DC') {
        $prefixe = if ($mode -eq 'AC') { 'Secteur' } else { 'Batterie' }

        foreach ($d in $delais) {
            $cle  = "{0}_{1}" -f $prefixe, $d.Cle
            $brut = Get-ValeurProfil -Profil $Profil -Cle $cle -Type $Type
            if ($null -eq $brut) { Write-Log "$cle non défini : paramètre laissé inchangé"; continue }
            $min = ConvertTo-Minutes -Valeur $brut -Nom $cle
            if ($null -eq $min) { continue }
            if ($d.Cle -eq 'VeilleProlongee' -and $min -gt 0 -and -not $HiberOK) {
                Write-Log "$cle = $min min mais l'hibernation est désactivée : forcé à 0 (jamais)" 'AVERT'
                $min = 0
            }
            Set-Parametre -Guid $Guid -Mode $mode -Sous $d.Sous -Param $d.Param -Valeur ($min * 60) `
                          -Libelle $d.Libelle -Affichage (Format-Minutes $min)
        }

        foreach ($a in $actions) {
            if ($a.Cle -eq 'Capot' -and $Type -eq 'Fixe') { continue }
            $cle  = "{0}_{1}" -f $prefixe, $a.Cle
            $brut = Get-ValeurProfil -Profil $Profil -Cle $cle -Type $Type
            if ($null -eq $brut) { Write-Log "$cle non défini : paramètre laissé inchangé"; continue }
            $code = Resolve-Action -Valeur $brut -Nom $cle -HiberOK $HiberOK -AutoriserEcran $a.Ecran
            if ($null -eq $code) { continue }
            Set-Parametre -Guid $Guid -Mode $mode -Sous 'SUB_BUTTONS' -Param $a.Param -Valeur $code `
                          -Libelle $a.Libelle -Affichage $Script:LibellesAction[$code]
        }

        # Veille hybride
        $brut = Get-Valeur $Profil 'VeilleHybride' $null
        if ($null -ne $brut) {
            $hybride = ConvertTo-Booleen $brut
            if ($hybride -and -not $HiberOK) {
                Write-Log "VeilleHybride ($prefixe) demandée mais l'hibernation est désactivée : désactivée" 'AVERT'
                $hybride = $false
            }
            Set-Parametre -Guid $Guid -Mode $mode -Sous 'SUB_SLEEP' -Param 'HYBRIDSLEEP' -Valeur ([int]$hybride) `
                          -Libelle 'Veille hybride' -Affichage $(if ($hybride) { 'Oui' } else { 'Non' })
        }

        # Minuteries de réveil
        $brut = Get-Valeur $Profil 'MinuteriesReveil' $null
        if ($null -ne $brut) {
            $cleMin = ConvertTo-Cle $brut
            if ($cleMin -like 'import*') { $val = 2; $aff = 'Importantes uniquement' }
            elseif (ConvertTo-Booleen $brut) { $val = 1; $aff = 'Oui' }
            else { $val = 0; $aff = 'Non' }
            Set-Parametre -Guid $Guid -Mode $mode -Sous 'SUB_SLEEP' -Param 'RTCWAKE' -Valeur $val `
                          -Libelle 'Minuteries de réveil' -Affichage $aff
        }
    }
}

function Install-Tache {
    param([string]$CheminConfig)
    $chemin    = $PSCommandPath
    $arguments = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$chemin`" -FichierConfig `"$CheminConfig`""

    if ($chemin -match '\\Users\\|\\Temp\\|^[A-Z]:\\\$Recycle') {
        Write-Log "Le script est situé dans '$chemin' : préférez un emplacement stable (ex. C:\ProgramData\Wisper\Veille)" 'AVERT'
    }
    if ($Script:ModeSimulation) {
        Write-Log "Création de la tâche '$($Script:NomTache)'   [powershell.exe $arguments]" 'SIMU'
        return
    }
    try {
        $action      = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $arguments
        $declencheur = New-ScheduledTaskTrigger -AtStartup
        $declencheur.Delay = 'PT1M'
        $compte      = New-ScheduledTaskPrincipal -UserId 'NT AUTHORITY\SYSTEM' -LogonType ServiceAccount -RunLevel Highest
        $reglages    = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries `
                                                    -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Minutes 10)
        $null = Register-ScheduledTask -TaskName $Script:NomTache -Action $action -Trigger $declencheur `
                                       -Principal $compte -Settings $reglages -Force `
                                       -Description 'Applique la configuration de veille W360 (W360-Veille.ps1) au démarrage'
        Write-Log "Tâche planifiée '$($Script:NomTache)' créée (au démarrage + 1 min, compte SYSTEM)" 'OK'
    }
    catch { Write-Log "Création de la tâche planifiée : ÉCHEC ($($_.Exception.Message))" 'ERREUR' }
}

function Uninstall-Tache {
    if (-not (Get-ScheduledTask -TaskName $Script:NomTache -ErrorAction SilentlyContinue)) {
        Write-Log "Tâche planifiée '$($Script:NomTache)' absente : rien à supprimer"
        return
    }
    if ($Script:ModeSimulation) { Write-Log "Suppression de la tâche '$($Script:NomTache)'" 'SIMU'; return }
    try {
        Unregister-ScheduledTask -TaskName $Script:NomTache -Confirm:$false
        Write-Log "Tâche planifiée '$($Script:NomTache)' supprimée" 'OK'
    }
    catch { Write-Log "Suppression de la tâche planifiée : ÉCHEC ($($_.Exception.Message))" 'ERREUR' }
}

function Restore-PlanWindows {
    $null = Invoke-Powercfg -Arguments @('/setactive', $Script:GuidEquilibre) -Description "Réactivation du mode 'Utilisation normale'"
    if ((& powercfg.exe /list) -match $Script:GuidPlan) {
        $null = Invoke-Powercfg -Arguments @('/delete', $Script:GuidPlan) -Description 'Suppression du mode dédié W360'
    }
    else { Write-Log 'Mode dédié absent : rien à supprimer' }
    Write-Log 'Note : hibernation et démarrage rapide ne sont pas modifiés par la restauration' 'INFO'
}

function Write-EtatsVeille {
    try {
        $ErrorActionPreference = 'Continue'
        Write-Log 'États de veille du matériel (powercfg /a) :'
        & powercfg.exe /a 2>&1 | ForEach-Object { "$_".Trim() } | Where-Object { $_ } | ForEach-Object { Write-Log "    $_" }
    }
    catch { }
}

function Complete-Execution {
    Write-Log ("Fin d'exécution : {0} erreur(s), {1} avertissement(s)" -f $Script:NbErreurs, $Script:NbAvert) `
              $(if ($Script:NbErreurs -gt 0) { 'ERREUR' } elseif ($Script:NbAvert -gt 0) { 'AVERT' } else { 'OK' })
    if ($Script:NbErreurs -gt 0 -and $Script:CodeSortie -eq 0) { $Script:CodeSortie = 1 }
}

# ---------------------------------------------------------------------------
#  Programme principal
# ---------------------------------------------------------------------------
function Main {
    # 1. Configuration + journal (attente éventuelle si le .ini est sur le réseau)
    if ($AttenteConfig -gt 0 -and -not (Test-Path -LiteralPath $FichierConfig)) {
        $limite = (Get-Date).AddSeconds($AttenteConfig)
        while (-not (Test-Path -LiteralPath $FichierConfig) -and (Get-Date) -lt $limite) { Start-Sleep -Seconds 5 }
    }
    if (-not (Test-Path -LiteralPath $FichierConfig)) {
        Initialize-Journal -Dossier (Join-Path ([IO.Path]::GetTempPath()) 'W360_Veille') -TailleMaxKo 512 -NbArchives 5
        Write-Log "Fichier de configuration introuvable : $FichierConfig" 'ERREUR'
        $Script:CodeSortie = 2; return
    }
    $cheminConfig = (Resolve-Path -LiteralPath $FichierConfig).Path
    $ini = Read-Ini -Chemin $cheminConfig
    $gen = Get-Section $ini 'General'
    $jrn = Get-Section $ini 'Journal'

    $dossierLog = [Environment]::ExpandEnvironmentVariables((Get-Valeur $jrn 'DossierLog' '%ProgramData%\Wisper\Veille\Logs'))
    Initialize-Journal -Dossier $dossierLog `
                       -TailleMaxKo (ConvertTo-Entier (Get-Valeur $jrn 'TailleMaxKo' 512) 512) `
                       -NbArchives  (ConvertTo-Entier (Get-Valeur $jrn 'NombreArchives' 5) 5)

    if (ConvertTo-Booleen (Get-Valeur $gen 'Simulation' 'Non')) { $Script:ModeSimulation = $true }

    Write-Log ('=' * 72)
    $identite = [Security.Principal.WindowsIdentity]::GetCurrent()
    $contexte = if ($identite.IsSystem) { 'SYSTEM (script de démarrage / tâche)' } else { $identite.Name }
    Write-Log "W360-Veille v$($Script:Version) - Poste : $env:COMPUTERNAME - Contexte : $contexte"
    try {
        $os = Get-CimInstance -ClassName Win32_OperatingSystem
        Write-Log "Système : $($os.Caption) ($($os.Version))"
    } catch { }
    Write-Log "Configuration : $cheminConfig"
    if ($Script:ModeSimulation) { Write-Log 'MODE SIMULATION : aucune modification ne sera appliquée' 'SIMU' }

    # 2. Droits
    if (-not (Test-Admin)) {
        if ($Script:ModeSimulation) { Write-Log 'Droits administrateur absents (toléré en simulation)' 'AVERT' }
        else {
            Write-Log "Ce script doit être exécuté en tant qu'administrateur" 'ERREUR'
            $Script:CodeSortie = 3; return
        }
    }

    # 3. Actions de maintenance
    if ($SupprimerTache) { Uninstall-Tache; return }
    if ($Restaurer)      { Restore-PlanWindows; return }
    if ($InstallerTache) { Install-Tache -CheminConfig $cheminConfig }

    # 4. Type de poste
    $demande = if ($TypePoste) { $TypePoste } else { Get-Valeur $gen 'TypePoste' 'Auto' }
    $type = switch -Regex (ConvertTo-Cle $demande) {
        '^port' { 'Portable'; break }
        '^fix'  { 'Fixe'; break }
        default { 'Auto' }
    }
    if ($type -eq 'Auto') { $type = Get-TypePosteDetecte }
    else { Write-Log "Type de poste forcé : $type" }

    $profil = Get-Section $ini $type
    if ($profil.Count -eq 0) {
        Write-Log "Section [$type] absente ou vide dans $cheminConfig" 'ERREUR'
        $Script:CodeSortie = 2; return
    }
    Write-Log "Profil appliqué : [$type]"

    # 5. Hibernation et démarrage rapide (paramètres globaux)
    $hiber   = ConvertTo-Booleen (Get-Valeur $gen 'Hibernation' 'Non')
    $ok      = Invoke-Powercfg -Arguments @('/hibernate', $(if ($hiber) { 'on' } else { 'off' })) `
                               -Description "Hibernation globale : $(if ($hiber) { 'activée' } else { 'désactivée' })"
    $hiberOK = $hiber -and $ok

    $rapide = ConvertTo-Booleen (Get-Valeur $gen 'DemarrageRapide' 'Non')
    if ($rapide -and -not $hiberOK) {
        Write-Log "DemarrageRapide=Oui ignoré : l'hibernation est désactivée" 'AVERT'
        $rapide = $false
    }
    Set-DemarrageRapide -Actif $rapide

    # 6. Mode d'alimentation cible
    $guid = Get-PlanCible -Dedie (ConvertTo-Booleen (Get-Valeur $gen 'PlanDedie' 'Oui')) `
                          -Nom (Get-Valeur $gen 'NomPlan' 'W360 - Gestion veille')
    if (-not $guid) {
        Write-Log "Aucun mode d'alimentation exploitable : arrêt" 'ERREUR'
        return
    }

    # 7. Délais, actions et options
    Set-ProfilVeille -Guid $guid -Profil $profil -Type $type -HiberOK $hiberOK

    $mdp = ConvertTo-Booleen (Get-Valeur $gen 'MotDePasseReveil' 'Oui')
    foreach ($m in 'AC', 'DC') {
        Set-Parametre -Guid $guid -Mode $m -Sous 'SUB_NONE' -Param 'CONSOLELOCK' -Valeur ([int]$mdp) `
                      -Libelle 'Mot de passe au réveil' -Affichage $(if ($mdp) { 'Oui' } else { 'Non' })
    }

    # 8. Activation (nécessaire pour prendre en compte les nouvelles valeurs)
    $null = Invoke-Powercfg -Arguments @('/setactive', $guid) -Description "Activation du mode d'alimentation $guid"

    Write-EtatsVeille
}

try { Main }
catch {
    Write-Log ("Erreur inattendue : {0} (ligne {1})" -f $_.Exception.Message, $_.InvocationInfo.ScriptLineNumber) 'ERREUR'
    $Script:CodeSortie = 1
}
Complete-Execution
exit $Script:CodeSortie

14.4 W360-Veille.cmd — Lanceur pour les tests manuels

Demande l'élévation de droits si nécessaire, puis exécute le script en transmettant les paramètres reçus. Ne pas l'utiliser dans la stratégie de groupe (voir § 3).

@echo off
setlocal
:: =====================================================================
::  W360-Veille - Lanceur
::  Demande l'elevation si besoin puis execute W360-Veille.ps1
::  Exemples :
::    W360-Veille.cmd
::    W360-Veille.cmd -Simulation
::    W360-Veille.cmd -TypePoste Portable
::    W360-Veille.cmd -InstallerTache
:: =====================================================================

net session >nul 2>&1
if %errorlevel% neq 0 (
    echo Elevation des droits administrateur...
    if "%~1"=="" (
        powershell.exe -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
    ) else (
        powershell.exe -NoProfile -Command "Start-Process -FilePath '%~f0' -ArgumentList '%*' -Verb RunAs"
    )
    exit /b
)

powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0W360-Veille.ps1" %*
set "RC=%errorlevel%"

echo.
if "%RC%"=="0" (echo Termine sans erreur.) else (echo Termine avec le code %RC% - consulter le journal.)
:: Pause uniquement en lancement manuel (double-clic, sans argument)
if "%~1"=="" pause
exit /b %RC%

14.5 Installer-Kit.cmd — Assistant d'installation sur le master

Copie le kit dans C:\ProgramData\Wisper\Veille, sécurise le dossier, lance une simulation, copie les paramètres de la stratégie de groupe dans le presse-papiers et ouvre gpedit.msc.

@echo off
setlocal
:: =====================================================================
::  W360-Veille - Installation du kit sur le poste master
::  1. Copie le kit dans C:\ProgramData\Wisper\Veille
::  2. Securise le dossier (SYSTEM et Administrateurs en ecriture seulement)
::  3. Lance une simulation
::  4. Copie la ligne de parametres GPO dans le presse-papiers
::  5. Ouvre l'editeur de strategie de groupe locale (gpedit.msc)
:: =====================================================================

set "CIBLE=C:\ProgramData\Wisper\Veille"

net session >nul 2>&1
if %errorlevel% neq 0 (
    echo Elevation des droits administrateur...
    powershell.exe -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
    exit /b
)

echo.
echo === 1/5 Copie du kit vers %CIBLE% ===
if /I "%~dp0"=="%CIBLE%\" (
    echo Le kit est deja dans le dossier cible, copie ignoree.
    goto :droits
)
if not exist "%CIBLE%" mkdir "%CIBLE%"
copy /Y "%~dp0W360-Veille.ps1" "%CIBLE%\" >nul || goto :erreur
copy /Y "%~dp0W360-Veille.cmd" "%CIBLE%\" >nul
copy /Y "%~dp0LISEZMOI.md"     "%CIBLE%\" >nul
if exist "%CIBLE%\W360-Veille.ini" (
    choice /C ON /M "Une configuration existe deja. La remplacer (O) ou la conserver (N)"
    if errorlevel 2 (
        echo Configuration existante conservee.
    ) else (
        copy /Y "%~dp0W360-Veille.ini" "%CIBLE%\" >nul
        echo Configuration remplacee.
    )
) else (
    copy /Y "%~dp0W360-Veille.ini" "%CIBLE%\" >nul || goto :erreur
)

:droits
echo.
echo === 2/5 Securisation du dossier ===
:: S-1-5-18 = SYSTEM, S-1-5-32-544 = Administrateurs, S-1-5-32-545 = Utilisateurs
icacls "%CIBLE%" /inheritance:r /grant:r "*S-1-5-18:(OI)(CI)F" "*S-1-5-32-544:(OI)(CI)F" "*S-1-5-32-545:(OI)(CI)RX" /T /C /Q
if %errorlevel% neq 0 echo ATTENTION : la securisation du dossier a echoue.

echo.
echo === 3/5 Simulation ===
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%CIBLE%\W360-Veille.ps1" -Simulation

echo.
echo === 4/5 Parametres a saisir dans la GPO locale ===
echo   Nom du script : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
echo   Parametres    : -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%CIBLE%\W360-Veille.ps1"
powershell.exe -NoProfile -Command "Set-Clipboard -Value '-NoProfile -NonInteractive -ExecutionPolicy Bypass -File \"%CIBLE%\W360-Veille.ps1\"'"
echo   (la ligne de parametres a ete copiee dans le presse-papiers)

echo.
echo === 5/5 Ouverture de gpedit.msc ===
echo   Configuration ordinateur ^> Parametres Windows ^> Scripts (demarrage/arret) ^> Demarrage ^> onglet Scripts ^> Ajouter
if exist "%windir%\System32\gpedit.msc" (
    start "" gpedit.msc
) else (
    echo   gpedit.msc introuvable : edition Windows 10 Famille non supportee.
)
echo.
pause
exit /b 0

:erreur
echo ERREUR : copie impossible vers %CIBLE%
pause
exit /b 1

Did this page help you?