<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Automation on kenji.blog</title><link>http://kenji.blog/fr/tags/automation/</link><description>Recent content in Automation on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 06:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/tags/automation/index.xml" rel="self" type="application/rss+xml"/><item><title>Exemple pratique d'automatisation complète des tâches quotidiennes avec des scripts PowerShell</title><link>http://kenji.blog/fr/p/powershell-daily-task-automation-scripts/</link><pubDate>Sun, 13 Sep 2026 06:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/powershell-daily-task-automation-scripts/</guid><description>&lt;img src="http://kenji.blog/p/powershell-daily-task-automation-scripts/img/eyecatch.jpg" alt="Featured image of post Exemple pratique d'automatisation complète des tâches quotidiennes avec des scripts PowerShell" />&lt;h2 id="introduction--pourquoi-automatiser-les-tâches-avec-powershell-">Introduction : Pourquoi automatiser les tâches avec PowerShell ?
&lt;/h2>&lt;p>Dans l&amp;rsquo;infrastructure informatique et les environnements de développement modernes, les « tâches de routine quotidiennes » sont un défi inévitable pour les utilisateurs ayant Windows pour plate-forme. Sauvegarder des fichiers, surveiller les journaux système, mettre à jour et compiler les ressources de développement (dépôts Git)&amp;hellip; effectuer ces tâches manuellement est un terrain propice aux erreurs humaines et conduit à une perte de temps précieux.&lt;/p>
&lt;p>Autrefois, les fichiers batch (&lt;code>.bat&lt;/code> ou &lt;code>.cmd&lt;/code>) ou VBScript étaient utilisés, mais aujourd&amp;rsquo;hui, la solution optimale est sans aucun doute &lt;strong>PowerShell&lt;/strong>. PowerShell n&amp;rsquo;est pas simplement un shell basé sur du texte, il est construit sur la puissante base orientée objet du .NET Framework (et .NET Core). Les données passées par le pipeline ne sont pas des « chaînes de caractères » mais des « objets », il n&amp;rsquo;est donc pas nécessaire d&amp;rsquo;implémenter soi-même une analyse de texte complexe (comme grep, awk ou sed) ; vous pouvez facilement accéder aux données en spécifiant simplement des propriétés.&lt;/p>
&lt;p>Dans cet article, nous présenterons trois exemples concrets de scripts d&amp;rsquo;automatisation complète directement liés au travail pratique utilisant PowerShell (sauvegarde vers un NAS et rotation des journaux, surveillance du journal des événements et notifications Slack, et mise à jour / compilation par lots de multiples dépôts Git). En outre, nous expliquerons en profondeur les technologies fondamentales nécessaires au préalable, telles que les politiques d&amp;rsquo;exécution de PowerShell, la modularisation et l&amp;rsquo;intégration du Planificateur de tâches.&lt;/p>
&lt;hr>
&lt;h2 id="préparer-les-bases-de-lautomatisation-powershell">Préparer les bases de l&amp;rsquo;automatisation PowerShell
&lt;/h2>&lt;p>Pour que les scripts d&amp;rsquo;automatisation fonctionnent de manière sûre et fiable dans un environnement de production, plusieurs préparatifs sont nécessaires. Ici, nous détaillerons la compréhension des politiques d&amp;rsquo;exécution, la modularisation pour améliorer la réutilisabilité, ainsi qu&amp;rsquo;une gestion robuste des erreurs.&lt;/p>
&lt;h3 id="1-politique-dexécution-de-powershell-execution-policy">1. Politique d&amp;rsquo;exécution de PowerShell (Execution Policy)
&lt;/h3>&lt;p>Sous Windows, par défaut, une « politique d&amp;rsquo;exécution » est configurée pour empêcher l&amp;rsquo;exécution accidentelle de scripts malveillants, et dans son état initial (&lt;code>Restricted&lt;/code>), aucun script (fichier &lt;code>.ps1&lt;/code>) ne peut être exécuté. Pour automatiser, il est nécessaire de changer cela à un niveau approprié.&lt;/p>
&lt;p>Les types de politiques d&amp;rsquo;exécution sont les suivants :&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Restricted&lt;/strong>: N&amp;rsquo;autorise pas l&amp;rsquo;exécution de scripts. (Par défaut)&lt;/li>
&lt;li>&lt;strong>AllSigned&lt;/strong>: N&amp;rsquo;autorise l&amp;rsquo;exécution que des scripts signés par un éditeur de confiance.&lt;/li>
&lt;li>&lt;strong>RemoteSigned&lt;/strong>: Les scripts créés localement peuvent être exécutés tels quels, mais les scripts téléchargés depuis Internet nécessitent une signature.&lt;/li>
&lt;li>&lt;strong>Unrestricted&lt;/strong>: Tous les scripts peuvent être exécutés, mais un avertissement s&amp;rsquo;affichera lors de l&amp;rsquo;exécution d&amp;rsquo;un script téléchargé depuis Internet.&lt;/li>
&lt;li>&lt;strong>Bypass&lt;/strong>: Rien n&amp;rsquo;est bloqué et aucun avertissement n&amp;rsquo;est affiché. Souvent utilisé pour l&amp;rsquo;exécution temporaire de scripts (comme les pipelines CI/CD).&lt;/li>
&lt;/ul>
&lt;p>Lors de l&amp;rsquo;exécution de vos propres scripts via le Planificateur de tâches dans un environnement d&amp;rsquo;entreprise local, le paramètre le plus réaliste et le plus sûr est &lt;code>RemoteSigned&lt;/code>. Lancez PowerShell avec les privilèges d&amp;rsquo;administrateur et exécutez la commande suivante :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Set-ExecutionPolicy&lt;/span> &lt;span class="n">RemoteSigned&lt;/span> &lt;span class="n">-Scope&lt;/span> &lt;span class="n">LocalMachine&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cela permettra aux scripts tels que les scripts de sauvegarde créés localement de fonctionner sans être bloqués.&lt;/p>
&lt;h3 id="2-réutilisation-du-code-par-la-modularisation-psm1--psd1">2. Réutilisation du code par la modularisation (.psm1 / .psd1)
&lt;/h3>&lt;p>Lors du traitement d&amp;rsquo;automatisations complexes, il n&amp;rsquo;est pas recommandé d&amp;rsquo;écrire tout le traitement dans un seul gros fichier &lt;code>.ps1&lt;/code> d&amp;rsquo;un point de vue de la maintenabilité. Les fonctions fréquemment utilisées (par exemple, la sortie du journal, l&amp;rsquo;envoi de Webhooks à Slack, la gestion des erreurs, etc.) doivent être séparées en « modules ».&lt;/p>
&lt;p>Les modules PowerShell se composent principalement d&amp;rsquo;un fichier de module de script (&lt;code>.psm1&lt;/code>) et d&amp;rsquo;un manifeste de module (&lt;code>.psd1&lt;/code>).&lt;/p>
&lt;p>Exemple de &lt;strong>CommonUtils.psm1&lt;/strong> :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">function&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Write-CustomLog&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">CmdletBinding&lt;/span>&lt;span class="p">()]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">param&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">Parameter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="na">Mandatory&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="vm">$true&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="no">string&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="nv">$Message&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">ValidateSet&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;WARNING&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;ERROR&amp;#39;&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="no">string&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="nv">$Level&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$timestamp&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s2">&amp;#34;yyyy-MM-dd HH:mm:ss&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$logLine&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;[&lt;/span>&lt;span class="nv">$timestamp&lt;/span>&lt;span class="s2">] [&lt;/span>&lt;span class="nv">$Level&lt;/span>&lt;span class="s2">] &lt;/span>&lt;span class="nv">$Message&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Exécuter à la fois la sortie à l&amp;#39;écran et la sortie dans le fichier&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="nv">$logLine&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Add-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\logs\automation.log&amp;#34;&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="nv">$logLine&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Export-ModuleMember&lt;/span> &lt;span class="n">-Function&lt;/span> &lt;span class="nb">Write-CustomLog&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Pour appeler ce module depuis un autre script, utilisez &lt;code>Import-Module&lt;/code> au début de votre script.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Import-Module&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Modules\CommonUtils.psm1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-CustomLog&lt;/span> &lt;span class="n">-Message&lt;/span> &lt;span class="s2">&amp;#34;Le processus de sauvegarde commence.&amp;#34;&lt;/span> &lt;span class="n">-Level&lt;/span> &lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-gestion-robuste-des-erreurs-try--catch">3. Gestion robuste des erreurs (try / catch)
&lt;/h3>&lt;p>Ce qui est le plus important dans l&amp;rsquo;automatisation, c&amp;rsquo;est « comment se comporter en cas d&amp;rsquo;échec ». Dans PowerShell, vous pouvez contrôler le comportement par défaut lorsqu&amp;rsquo;une commande échoue en définissant la variable intégrée &lt;code>$ErrorActionPreference&lt;/code>. Par défaut, c&amp;rsquo;est &lt;code>Continue&lt;/code> (afficher l&amp;rsquo;erreur et continuer le traitement), mais dans les scripts d&amp;rsquo;automatisation, la meilleure pratique est de le définir sur &lt;code>Stop&lt;/code> et de capturer explicitement les exceptions avec un bloc &lt;code>try / catch&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Traitement susceptible d&amp;#39;échouer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$content&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\NonExistentFile.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">System.Management.Automation.ItemNotFoundException&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Capturer une erreur spécifique&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Le fichier est introuvable : &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Capturer toutes les autres erreurs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Une erreur inattendue s&amp;#39;est produite : &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">finally&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Processus de nettoyage qui est toujours exécuté quel que soit le succès ou l&amp;#39;échec&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Le processus se termine.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En tirant parti de cette base, vous pouvez créer des scripts sûrs et traçables même lorsqu&amp;rsquo;ils fonctionnent sans surveillance la nuit.&lt;/p>
&lt;hr>
&lt;h2 id="intégration-au-planificateur-de-tâches-register-scheduledtask">Intégration au Planificateur de tâches (Register-ScheduledTask)
&lt;/h2>&lt;p>Une fois le script terminé, vous avez ensuite besoin d&amp;rsquo;un mécanisme pour l&amp;rsquo;exécuter régulièrement. Sous Windows, l&amp;rsquo;option la plus fiable est le « Planificateur de tâches ». Bien qu&amp;rsquo;il soit possible de le configurer via l&amp;rsquo;interface graphique (&lt;code>taskschd.msc&lt;/code>), dans l&amp;rsquo;optique de coder les manuels d&amp;rsquo;infrastructure (Infrastructure as Code), nous expliquerons comment enregistrer des tâches à l&amp;rsquo;aide des applets de commande PowerShell.&lt;/p>
&lt;p>PowerShell dispose du module &lt;code>ScheduledTasks&lt;/code>, qui vous permet de définir de manière détaillée le déclencheur (quand l&amp;rsquo;exécuter), l&amp;rsquo;action (ce qu&amp;rsquo;il faut exécuter) et le principal (avec quels privilèges d&amp;rsquo;utilisateur l&amp;rsquo;exécuter).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. Définition de l&amp;#39;action (Exécuter PowerShell en mode masqué et lui passer le script spécifié)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$action&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskAction&lt;/span> &lt;span class="n">-Execute&lt;/span> &lt;span class="s2">&amp;#34;powershell.exe&amp;#34;&lt;/span> &lt;span class="n">-Argument&lt;/span> &lt;span class="s2">&amp;#34;-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Scripts\DailyTasks.ps1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 2. Définition du déclencheur (Exécuter tous les jours à 3h00 du matin)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$trigger&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskTrigger&lt;/span> &lt;span class="n">-Daily&lt;/span> &lt;span class="n">-At&lt;/span> &lt;span class="s2">&amp;#34;3:00AM&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 3. Définition du principal (Privilèges de l&amp;#39;utilisateur exécutant) (Exécuter avec les privilèges SYSTEM)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$principal&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskPrincipal&lt;/span> &lt;span class="n">-UserId&lt;/span> &lt;span class="s2">&amp;#34;NT AUTHORITY\SYSTEM&amp;#34;&lt;/span> &lt;span class="n">-LogonType&lt;/span> &lt;span class="n">ServiceAccount&lt;/span> &lt;span class="n">-RunLevel&lt;/span> &lt;span class="n">Highest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 4. Création des paramètres de la tâche&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$settings&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskSettingsSet&lt;/span> &lt;span class="n">-AllowStartIfOnBatteries&lt;/span> &lt;span class="n">-DontStopIfGoingOnBatteries&lt;/span> &lt;span class="n">-StartWhenAvailable&lt;/span> &lt;span class="n">-DontStopOnIdleEnd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 5. Enregistrement de la tâche&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$taskName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;MyDailyAutomationTask&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Register-ScheduledTask&lt;/span> &lt;span class="n">-TaskName&lt;/span> &lt;span class="nv">$taskName&lt;/span> &lt;span class="n">-Action&lt;/span> &lt;span class="nv">$action&lt;/span> &lt;span class="n">-Trigger&lt;/span> &lt;span class="nv">$trigger&lt;/span> &lt;span class="n">-Principal&lt;/span> &lt;span class="nv">$principal&lt;/span> &lt;span class="n">-Settings&lt;/span> &lt;span class="nv">$settings&lt;/span> &lt;span class="n">-Description&lt;/span> &lt;span class="s2">&amp;#34;Tâche pour exécuter automatiquement les tâches de routine quotidiennes&amp;#34;&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Le simple fait d&amp;rsquo;exécuter ce script enregistre le travail dans le Planificateur de tâches et le script s&amp;rsquo;exécutera tous les jours à l&amp;rsquo;heure spécifiée avec les privilèges SYSTEM (les privilèges les plus élevés, en arrière-plan et sans afficher d&amp;rsquo;écran).&lt;/p>
&lt;hr>
&lt;h2 id="exemple-pratique-1--sauvegarde-vers-un-nas-externe-et-rotation-des-journaux">Exemple pratique 1 : Sauvegarde vers un NAS externe et rotation des journaux
&lt;/h2>&lt;p>Les sauvegardes quotidiennes de vos données de travail sont essentielles, mais la copie manuelle est hors de question. Ici, nous allons créer un script qui appelle &lt;code>Robocopy&lt;/code>, la commande de copie la plus puissante intégrée à Windows, depuis PowerShell, génère un journal des résultats d&amp;rsquo;exécution et supprime (fait tourner) automatiquement les anciens journaux.&lt;/p>
&lt;h3 id="valeur-théorique-du-temps-dexécution-dans-les-transferts-réseau-math">Valeur théorique du temps d&amp;rsquo;exécution dans les transferts réseau (Math)
&lt;/h3>&lt;p>Lors de la conception d&amp;rsquo;un script de sauvegarde, il est opérationnellement important d&amp;rsquo;estimer combien de temps il faudra pour terminer le processus. Le temps estimé $T_{backup}$ requis pour la sauvegarde sur un NAS via un réseau peut être approché par la formule suivante.&lt;/p>
$$ T_{backup} = \frac{S_{total}}{B \times (1 - \alpha)} + C \times L $$&lt;p>Ici, chaque variable est la suivante :&lt;/p>
&lt;ul>
&lt;li>$S_{total}$ : Quantité totale de données à sauvegarder (Bits)&lt;/li>
&lt;li>$B$ : Bande passante du réseau (bps, Ex : 1 Gbps = $10^9$ bps)&lt;/li>
&lt;li>$\alpha$ : Surcharge du réseau et des protocoles (généralement de 0,1 à 0,2 pour TCP/IP ou les protocoles SMB)&lt;/li>
&lt;li>$C$ : Nombre total de fichiers&lt;/li>
&lt;li>$L$ : Latence de traitement par fichier (secondes)&lt;/li>
&lt;/ul>
&lt;p>Surtout lors de la sauvegarde d&amp;rsquo;un grand nombre de petits fichiers (tels que le code source), le terme de délai dû au nombre de fichiers $C$ ($C \times L$) devient prédominant. C&amp;rsquo;est pourquoi, dans les processus de sauvegarde, il est optimal d&amp;rsquo;utiliser &lt;code>Robocopy&lt;/code>, qui permet des transferts multi-threads, plutôt qu&amp;rsquo;un simple outil de copie de fichiers.&lt;/p>
&lt;h3 id="flux-de-traitement-du-script-de-sauvegarde">Flux de traitement du script de sauvegarde
&lt;/h3>&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Démarrer le script de sauvegarde&amp;#34;] --&amp;gt; B{&amp;#34;Le NAS est-il accessible ?&amp;#34;}
B -- Oui --&amp;gt; C[&amp;#34;Exécuter Robocopy (Multi-thread)&amp;#34;]
B -- Non --&amp;gt; D[&amp;#34;Écrire le journal des erreurs et Quitter&amp;#34;]
C --&amp;gt; E{&amp;#34;Robocopy a-t-il réussi ?&amp;#34;}
E -- Oui (ExitCode &amp;lt; 8) --&amp;gt; F[&amp;#34;Rotation des journaux (Garder les 30 derniers jours)&amp;#34;]
E -- Non (ExitCode &amp;gt;= 8) --&amp;gt; D
F --&amp;gt; G[&amp;#34;Terminer le script de sauvegarde&amp;#34;]
D --&amp;gt; G
&lt;/pre>
&lt;h3 id="exemple-dimplémentation-de-script-powershell-backup-tonasps1">Exemple d&amp;rsquo;implémentation de script PowerShell (&lt;code>Backup-ToNas.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Valeurs de configuration&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$SourceDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\WorkData&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$TargetNasDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;\\NAS01\Backup\WorkData&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$LogDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Logs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$DateStr&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s2">&amp;#34;yyyyMMdd&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$LogFile&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="s2">&amp;#34;Backup_&lt;/span>&lt;span class="nv">$DateStr&lt;/span>&lt;span class="s2">.log&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$RetainDays&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mf">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 1. Vérification préalable : Le NAS est-il accessible ?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-not&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="s2">&amp;#34;Le chemin cible sur le NAS n&amp;#39;est pas accessible : &lt;/span>&lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Démarrage de la sauvegarde : &lt;/span>&lt;span class="nv">$SourceDir&lt;/span>&lt;span class="s2"> -&amp;gt; &lt;/span>&lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 2. Exécution de Robocopy&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /MIR : Mise en miroir (Supprime les fichiers absents de la source)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /MT:16 : Copie multi-thread avec 16 threads&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /NP : Ne pas afficher la progression en % (pour éviter de polluer le journal)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /R:2 /W:2 : 2 tentatives en cas d&amp;#39;erreur, 2 secondes d&amp;#39;attente&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$roboArgs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$SourceDir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/MIR&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/MT:16&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/NP&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/R:2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/W:2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/LOG+:&lt;/span>&lt;span class="nv">$LogFile&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Start-Process est le plus fiable pour appeler des commandes externes depuis PowerShell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$process&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Start-Process&lt;/span> &lt;span class="n">-FilePath&lt;/span> &lt;span class="s2">&amp;#34;robocopy.exe&amp;#34;&lt;/span> &lt;span class="n">-ArgumentList&lt;/span> &lt;span class="nv">$roboArgs&lt;/span> &lt;span class="n">-Wait&lt;/span> &lt;span class="n">-NoNewWindow&lt;/span> &lt;span class="n">-PassThru&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$exitCode&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$process&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ExitCode&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Spécifications du code de sortie (ExitCode) de Robocopy : 0 à 7 signifient un succès ou un fonctionnement prévu. 8 ou plus signifient une erreur&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$exitCode&lt;/span> &lt;span class="o">-ge&lt;/span> &lt;span class="mf">8&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="s2">&amp;#34;Robocopy s&amp;#39;est terminé avec une erreur. ExitCode : &lt;/span>&lt;span class="nv">$exitCode&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;La sauvegarde s&amp;#39;est terminée avec succès. ExitCode : &lt;/span>&lt;span class="nv">$exitCode&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 3. Rotation des journaux&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Suppression des anciens fichiers journaux (Période de rétention : &lt;/span>&lt;span class="nv">${RetainDays}&lt;/span>&lt;span class="s2"> jours)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$limitDate&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Get-Date&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="py">AddDays&lt;/span>&lt;span class="p">(-&lt;/span>&lt;span class="nv">$RetainDays&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="n">-Filter&lt;/span> &lt;span class="s2">&amp;#34;Backup_*.log&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Where-Object&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">LastWriteTime&lt;/span> &lt;span class="o">-lt&lt;/span> &lt;span class="nv">$limitDate&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Remove-Item&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Le nettoyage des journaux est terminé.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$errorMessage&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Une erreur s&amp;#39;est produite lors de la sauvegarde : &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="nv">$errorMessage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Écrire dans le fichier journal d&amp;#39;erreurs réel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Add-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="s2">&amp;#34;Error.log&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="s2">&amp;#34;[(Get-Date -Format &amp;#39;yyyy-MM-dd HH:mm:ss&amp;#39;)] &lt;/span>&lt;span class="nv">$errorMessage&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Quitter avec une valeur non nulle pour notifier l&amp;#39;erreur au planificateur de tâches&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span> &lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ce script, combiné au Planificateur de tâches, permet une sauvegarde quotidienne entièrement automatisée. La gestion du code de sortie (ExitCode) de &lt;code>Robocopy&lt;/code> est particulièrement importante. Gardez à l&amp;rsquo;esprit qu&amp;rsquo;une simple vérification &lt;code>$LASTEXITCODE -eq 0&lt;/code> ne fonctionnera pas correctement, car Robocopy renvoie 1 même en cas de succès si « de nouveaux fichiers ont été copiés », ou 2 si « des fichiers supplémentaires ont été supprimés », etc.&lt;/p>
&lt;hr>
&lt;h2 id="exemple-pratique-2--surveillance-du-journal-des-événements-système-et-notification-slack-webhook">Exemple pratique 2 : Surveillance du journal des événements système et notification Slack (Webhook)
&lt;/h2>&lt;p>Sur un serveur Windows ou une station de travail pour créateurs, il est extrêmement important de détecter de manière précoce les erreurs de disque, qui sont les signes avant-coureurs d&amp;rsquo;un écran bleu (BSoD), ou les plantages d&amp;rsquo;applications (Application Error).
Nous allons créer ici un script qui extrait les journaux de niveau « Erreur » et « Critique » des journaux d&amp;rsquo;événements &lt;code>System&lt;/code> et &lt;code>Application&lt;/code> de la dernière heure, et envoie une notification à Slack s&amp;rsquo;ils sont trouvés.&lt;/p>
&lt;h3 id="diagramme-de-séquence-du-processus-de-notification">Diagramme de séquence du processus de notification
&lt;/h3>&lt;pre class="mermaid">
sequenceDiagram
participant S as &amp;#34;Tâche planifiée&amp;#34;
participant P as &amp;#34;Script PowerShell&amp;#34;
participant W as &amp;#34;Journal d&amp;#39;événements Windows&amp;#34;
participant Sl as &amp;#34;API Slack&amp;#34;
S-&amp;gt;&amp;gt;P: &amp;#34;Déclencher le script (Toutes les heures)&amp;#34;
P-&amp;gt;&amp;gt;W: &amp;#34;Get-WinEvent (Critique/Erreur de la dernière heure)&amp;#34;
W--&amp;gt;&amp;gt;P: &amp;#34;Retourner les objets de journal&amp;#34;
alt &amp;#34;Erreurs trouvées&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;Formater le message (JSON)&amp;#34;
P-&amp;gt;&amp;gt;Sl: &amp;#34;Invoke-RestMethod (POST webhook_url)&amp;#34;
Sl--&amp;gt;&amp;gt;P: &amp;#34;200 OK&amp;#34;
else &amp;#34;Aucune erreur&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;Quitter normalement&amp;#34;
end
&lt;/pre>
&lt;h3 id="exemple-dimplémentation-de-script-powershell-monitor-eventlogps1">Exemple d&amp;rsquo;implémentation de script PowerShell (&lt;code>Monitor-EventLog.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Slack Webhook URL (Obtenue au préalable via l&amp;#39;intégration Incoming Webhooks de Slack)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$SlackWebhookUrl&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXXXXXXX&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Plage horaire de recherche (la dernière heure)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$startTime&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Get-Date&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="py">AddHours&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">-1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Utilisation de filtres XPath pour rechercher rapidement dans le journal des événements&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Niveau 1 : Critique (Critical), 2 : Erreur (Error)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$xmlFilter&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="sh">@&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;lt;QueryList&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Query Id=&amp;#34;0&amp;#34; Path=&amp;#34;System&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Select Path=&amp;#34;System&amp;#34;&amp;gt;*[System[(Level=1 or Level=2) and TimeCreated[@SystemTime&amp;amp;gt;=&amp;#39;&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$startTime&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToUniversalTime&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;o&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="sh">&amp;#39;]]]&amp;lt;/Select&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;/Query&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Query Id=&amp;#34;1&amp;#34; Path=&amp;#34;Application&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Select Path=&amp;#34;Application&amp;#34;&amp;gt;*[System[(Level=1 or Level=2) and TimeCreated[@SystemTime&amp;amp;gt;=&amp;#39;&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$startTime&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToUniversalTime&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;o&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="sh">&amp;#39;]]]&amp;lt;/Select&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;/Query&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;lt;/QueryList&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;#34;@&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Obtenir les journaux avec Get-WinEvent&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># -ErrorAction SilentlyContinue est pour ignorer l&amp;#39;erreur quand aucun journal n&amp;#39;est trouvé&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$events&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-WinEvent&lt;/span> &lt;span class="n">-FilterXml&lt;/span> &lt;span class="nv">$xmlFilter&lt;/span> &lt;span class="n">-ErrorAction&lt;/span> &lt;span class="n">SilentlyContinue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$events&lt;/span> &lt;span class="o">-and&lt;/span> &lt;span class="nv">$events&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$eventCount&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$events&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$eventCount&lt;/span>&lt;span class="s2"> journaux critiques/d&amp;#39;erreur ont été trouvés au cours de la dernière heure.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Construire le texte pour la notification&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;*Alerte Système Windows* :rotating_light:&lt;/span>&lt;span class="se">`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$eventCount&lt;/span>&lt;span class="s2"> erreurs ont été détectées au cours de la dernière heure.&lt;/span>&lt;span class="se">`n`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># N&amp;#39;inclure que les détails des 3 plus récentes (en tenant compte des limites de caractères, etc.)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$events&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Select-Object&lt;/span> &lt;span class="n">-First&lt;/span> &lt;span class="mf">3&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ForEach-Object&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;*&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">LogName&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">* - &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ProviderName&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2"> (EventID : &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">)&lt;/span>&lt;span class="se">`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt; &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Message&lt;/span> &lt;span class="o">-replace&lt;/span> &lt;span class="s1">&amp;#39;`n&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39; &amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="se">`n`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$eventCount&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;※ Il y a &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$eventCount&lt;/span> &lt;span class="p">-&lt;/span> &lt;span class="mf">3&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2"> autres erreurs. Veuillez vérifier l&amp;#39;Observateur d&amp;#39;événements.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Création du payload JSON à envoyer à Slack&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$payload&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$messageBody&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">username&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;SystemMonitor&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">icon_emoji&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;:desktop_computer:&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$jsonPayload&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$payload&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ConvertTo-Json&lt;/span> &lt;span class="n">-Depth&lt;/span> &lt;span class="mf">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Appeler l&amp;#39;API REST pour envoyer à Slack&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Invoke-RestMethod&lt;/span> &lt;span class="n">-Uri&lt;/span> &lt;span class="nv">$SlackWebhookUrl&lt;/span> &lt;span class="n">-Method&lt;/span> &lt;span class="n">Post&lt;/span> &lt;span class="n">-Body&lt;/span> &lt;span class="nv">$jsonPayload&lt;/span> &lt;span class="n">-ContentType&lt;/span> &lt;span class="s2">&amp;#34;application/json; charset=utf-8&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;La notification à Slack est terminée.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Aucun journal critique/d&amp;#39;erreur n&amp;#39;a été trouvé. Le système est normal.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="s2">&amp;#34;Une erreur s&amp;#39;est produite dans le script de surveillance du journal des événements : &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span> &lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Le point technique clé de ce script est l&amp;rsquo;utilisation de &lt;code>Get-WinEvent -FilterXml&lt;/code>. Le filtrage avec l&amp;rsquo;applet de commande classique &lt;code>Get-EventLog&lt;/code> ou &lt;code>Where-Object&lt;/code> via le pipeline charge tous les objets d&amp;rsquo;événements en mémoire avant le traitement, ce qui rend l&amp;rsquo;exécution très lente. En utilisant un filtre XML, le filtrage est effectué du côté du service des journaux d&amp;rsquo;événements Windows, ce qui permet d&amp;rsquo;obtenir une amélioration spectaculaire des performances, réduisant le temps d&amp;rsquo;exécution à quelques secondes.&lt;/p>
&lt;hr>
&lt;h2 id="exemple-pratique-3--mise-à-jour-en-lot-et-automatisation-de-la-compilation-de-multiples-dépôts-git">Exemple pratique 3 : Mise à jour en lot et automatisation de la compilation de multiples dépôts Git
&lt;/h2>&lt;p>Pour un développeur, c&amp;rsquo;est très fastidieux de synchroniser dès le matin tous les multiples dépôts Git (front-end, back-end, dépôts d&amp;rsquo;infrastructure, etc.) présents sur son PC de travail avec la dernière branche &lt;code>main&lt;/code>, et d&amp;rsquo;exécuter si besoin les commandes d&amp;rsquo;installation de paquets (comme &lt;code>npm install&lt;/code>) ou de compilation.
Nous allons créer un outil qui réalise cela en lot avec un script PowerShell.&lt;/p>
&lt;p>Ce script détectera automatiquement tous les dépôts Git sous un répertoire parent spécifique, et s&amp;rsquo;il n&amp;rsquo;y a pas de modifications non commitées, il exécutera &lt;code>git pull&lt;/code>. De plus, si de nouvelles modifications ont été récupérées, il lancera automatiquement la commande de compilation.&lt;/p>
&lt;h3 id="script-de-mise-à-jour-automatique-de-multiples-dépôts-update-gitreposps1">Script de mise à jour automatique de multiples dépôts (&lt;code>Update-GitRepos.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Liste des répertoires parents où se trouvent les dépôts&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$TargetDirectories&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;C:\Dev\FrontendProjects&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;C:\Dev\BackendProjects&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Explorer chaque répertoire&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$parentDir&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$TargetDirectories&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-not&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$parentDir&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Warning&lt;/span> &lt;span class="s2">&amp;#34;Le répertoire est introuvable : &lt;/span>&lt;span class="nv">$parentDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Obtenir la liste des sous-répertoires&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$subDirs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$parentDir&lt;/span> &lt;span class="n">-Directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$repoDir&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$subDirs&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$repoPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$repoDir&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">FullName&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$gitDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$repoPath&lt;/span> &lt;span class="s2">&amp;#34;.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Vérifier si le dossier .git existe (si c&amp;#39;est un dépôt Git)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$gitDir&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;---------------------------------&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Traitement du dépôt : &lt;/span>&lt;span class="nv">$repoPath&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Cyan&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Changer le répertoire de travail actuel de PowerShell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Set-Location&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$repoPath&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Vérifier s&amp;#39;il y a des modifications non commitées&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$status&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="n">status&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-porcelain&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$status&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Ignoré car il y a des modifications non commitées.&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Yellow&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Obtenir la branche actuelle&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$branch&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="nb">rev-parse&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-abbrev-ref&lt;/span> &lt;span class="n">HEAD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$branch&lt;/span> &lt;span class="o">-ne&lt;/span> &lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span> &lt;span class="o">-and&lt;/span> &lt;span class="nv">$branch&lt;/span> &lt;span class="o">-ne&lt;/span> &lt;span class="s2">&amp;#34;master&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Ignoré car la branche actuelle est &lt;/span>&lt;span class="nv">$branch&lt;/span>&lt;span class="s2"> (seuls main/master sont ciblés).&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Yellow&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Exécuter Pull et stocker le résultat dans une variable&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Récupération de la dernière version depuis le distant (git pull)...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$pullResult&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="n">pull&lt;/span> &lt;span class="n">origin&lt;/span> &lt;span class="nv">$branch&lt;/span> &lt;span class="mf">2&lt;/span>&lt;span class="p">&amp;gt;&amp;amp;&lt;/span>&lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Afficher également dans la console&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$pullResult&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ForEach-Object&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34; &lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># S&amp;#39;il y a une chaîne autre que &amp;#34;Already up to date.&amp;#34;, considérer qu&amp;#39;il y a eu une mise à jour&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$isUpdated&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">$false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$line&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$pullResult&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$line&lt;/span> &lt;span class="o">-notmatch&lt;/span> &lt;span class="s2">&amp;#34;Already up to date&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$isUpdated&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">$true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$isUpdated&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Le dépôt a été mis à jour. Démarrage de la tâche de compilation...&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Green&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># S&amp;#39;il y a un fichier package.json, exécuter npm install et npm run build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="s2">&amp;#34;package.json&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Exécution de npm install...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">npm&lt;/span> &lt;span class="n">install&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Exécution de npm run build...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">npm&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># S&amp;#39;il y a un fichier .sln (Solution Visual Studio), exécuter msbuild ou dotnet build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$slnFiles&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Filter&lt;/span> &lt;span class="s2">&amp;#34;*.sln&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$slnFiles&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Compilation de l&amp;#39;application .NET...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dotnet&lt;/span> &lt;span class="n">build&lt;/span> &lt;span class="nv">$slnFiles&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mf">0&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="py">FullName&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="s2">&amp;#34;Une erreur s&amp;#39;est produite lors du traitement du dépôt &lt;/span>&lt;span class="nv">$repoPath&lt;/span>&lt;span class="s2"> : &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;---------------------------------&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Le processus de mise à jour pour tous les dépôts est terminé.&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Green&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ce script est conçu de telle manière que même si une erreur se produit, les blocs &lt;code>try / catch&lt;/code> et la boucle &lt;code>foreach&lt;/code> lui permettent de continuer sans affecter le traitement du dépôt suivant. Il utilise également l&amp;rsquo;option &lt;code>git status --porcelain&lt;/code>, qui est destinée aux scripts, pour déterminer de manière fiable la propreté de l&amp;rsquo;arbre de travail. Si vous placez ce script dans votre dossier de démarrage ou l&amp;rsquo;enregistrez dans le Planificateur de tâches à l&amp;rsquo;ouverture de session de l&amp;rsquo;utilisateur, tout votre environnement de développement sera à jour pendant que vous démarrez votre PC et allez vous chercher un café.&lt;/p>
&lt;hr>
&lt;h2 id="points-dattention-opérationnelle-et-techniques-avancées">Points d&amp;rsquo;attention opérationnelle et techniques avancées
&lt;/h2>&lt;p>Il existe un certain nombre de bonnes pratiques à garder à l&amp;rsquo;esprit lors de l&amp;rsquo;exécution de scripts d&amp;rsquo;automatisation PowerShell sur de longues périodes.&lt;/p>
&lt;h3 id="1-gestion-sécurisée-des-informations-didentification">1. Gestion sécurisée des informations d&amp;rsquo;identification
&lt;/h3>&lt;p>Coder en dur des mots de passe ou des clés d&amp;rsquo;API (par exemple, des URL Slack Webhook, des chaînes de connexion à une base de données) en texte clair dans votre script est un risque de sécurité majeur. PowerShell dispose de fonctionnalités intégrées, telles que &lt;code>Export-Clixml&lt;/code> et &lt;code>ConvertFrom-SecureString&lt;/code>, pour chiffrer et enregistrer les informations d&amp;rsquo;identification.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Exécution manuelle la première fois uniquement (affiche une boîte de dialogue pour la saisie du mot de passe)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Get-Credential | Export-Clixml -Path &amp;#34;C:\Scripts\Creds\admin.xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Chargement à l&amp;#39;intérieur du script d&amp;#39;automatisation&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$cred&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Import-Clixml&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Creds\admin.xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Utiliser $cred pour se connecter à un serveur distant, etc.&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cela permet une gestion sécurisée des informations d&amp;rsquo;identification qui ne peuvent être déchiffrées que par le profil de l&amp;rsquo;utilisateur exécutant le script.&lt;/p>
&lt;h3 id="2-enregistrement-complet-du-journal-dexécution-via-les-transcriptions-transcript">2. Enregistrement complet du journal d&amp;rsquo;exécution via les transcriptions (Transcript)
&lt;/h3>&lt;p>Dans l&amp;rsquo;exemple précédent, les journaux étaient sortis individuellement en utilisant &lt;code>Add-Content&lt;/code> et des méthodes similaires, mais PowerShell a une fonctionnalité de transcription qui écrit automatiquement toutes les informations affichées à l&amp;rsquo;écran (y compris les messages d&amp;rsquo;erreur et la sortie standard) dans un fichier.&lt;/p>
&lt;p>En écrivant simplement ce qui suit au début et à la fin de votre script, vous pouvez créer un journal d&amp;rsquo;audit robuste.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Start-Transcript&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Logs\Execution_&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s1">&amp;#39;yyyyMMdd_HHmmss&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">.log&amp;#34;&lt;/span> &lt;span class="n">-Append&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># (Le traitement principal du script va ici)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Stop-Transcript&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-approche-mathématique-du-suivi-et-détection-des-anomalies-math">3. Approche mathématique du suivi et détection des anomalies (Math)
&lt;/h3>&lt;p>Dans l&amp;rsquo;automatisation à grande échelle, il est efficace non seulement de détecter de simples erreurs, mais aussi d&amp;rsquo;utiliser des méthodes statistiques pour détecter un comportement « inhabituel ». Par exemple, si le temps de sauvegarde quotidienne s&amp;rsquo;écarte de manière significative de la moyenne habituelle, cela peut être le signe avant-coureur d&amp;rsquo;une anomalie réseau ou d&amp;rsquo;une défaillance de disque.&lt;/p>
&lt;p>Si l&amp;rsquo;on considère les temps de sauvegarde quotidiens comme $x_1, x_2, \dots, x_n$, la moyenne de l&amp;rsquo;échantillon $\mu$ et l&amp;rsquo;écart type $\sigma$ sont calculés comme suit.&lt;/p>
$$ \mu = \frac{1}{n} \sum_{i=1}^n x_i $$$$ \sigma = \sqrt{ \frac{1}{n-1} \sum_{i=1}^n (x_i - \mu)^2 } $$&lt;p>Si le temps d&amp;rsquo;exécution d&amp;rsquo;aujourd&amp;rsquo;hui $x_{today}$ dépasse $\mu + 3\sigma$ (règle des trois sigmas), il est possible de mettre en place une logique qui avertira que le système a considéré qu&amp;rsquo;« une anomalie statistique s&amp;rsquo;est produite ». En utilisant l&amp;rsquo;applet de commande &lt;code>Measure-Object&lt;/code> de PowerShell, un tel traitement statistique peut être implémenté en seulement quelques lignes.&lt;/p>
&lt;h2 id="résumé">Résumé
&lt;/h2>&lt;p>Dans cet article, nous avons expliqué, avec des exemples concrets, l&amp;rsquo;automatisation complète des tâches de routine quotidiennes à l&amp;rsquo;aide de PowerShell dans un environnement Windows.
À partir de la création d&amp;rsquo;une base par la gestion de la politique d&amp;rsquo;exécution et la modularisation, nous avons présenté des scripts immédiatement applicables dans la pratique, tels que la sauvegarde et la rotation des journaux, la surveillance du journal des événements et la notification Slack, ou encore la compilation automatique de multiples dépôts Git.&lt;/p>
&lt;p>PowerShell est un moteur d&amp;rsquo;automatisation très profond et puissant qui, bien qu&amp;rsquo;étant un outil en ligne de commande, a accès à presque toutes les fonctionnalités de .NET. En utilisant les scripts présentés cette fois-ci comme base, vous pouvez personnaliser les chemins et la logique de traitement selon votre environnement de travail, vous libérant ainsi des tâches manuelles fastidieuses pour gagner un temps créatif.&lt;/p>
&lt;p>Le succès de l&amp;rsquo;automatisation repose sur le fait de « commencer par un petit script et d&amp;rsquo;augmenter progressivement la robustesse, comme la gestion des erreurs et la sortie des journaux ». Pourquoi ne pas commencer votre parcours d&amp;rsquo;automatisation avec PowerShell en sauvegardant d&amp;rsquo;abord un seul dossier sur votre PC ?&lt;/p></description></item><item><title>Intégration de PowerShell et C++ : Techniques d'automatisation de la gestion système</title><link>http://kenji.blog/fr/p/powershell-cpp-system-automation/</link><pubDate>Sat, 12 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/powershell-cpp-system-automation/</guid><description>&lt;img src="http://kenji.blog/p/powershell-cpp-system-automation/img/eyecatch.jpg" alt="Featured image of post Intégration de PowerShell et C++ : Techniques d'automatisation de la gestion système" />&lt;h2 id="introduction">Introduction
&lt;/h2>&lt;p>Dans l&amp;rsquo;administration et l&amp;rsquo;automatisation des systèmes Windows, PowerShell est devenu l&amp;rsquo;outil standard de facto. Vous pouvez écrire des scripts pour toutes sortes de tâches telles que la gestion d&amp;rsquo;Active Directory, les opérations sur le système de fichiers et la modification des configurations réseau. Cependant, bien que PowerShell soit polyvalent, il existe des situations où vous pouvez être confronté aux limites de performances inhérentes aux langages de script ou rencontrer des difficultés pour accéder aux API Windows de très bas niveau.&lt;/p>
&lt;p>Une solution puissante à ce problème est « l&amp;rsquo;intégration avec C++ ». C++ offre une vitesse d&amp;rsquo;exécution native et un accès complet à l&amp;rsquo;API Win32 et aux objets COM. En combinant la « productivité et flexibilité élevées » de PowerShell avec les « performances écrasantes et le contrôle de bas niveau » de C++, il devient possible d&amp;rsquo;optimiser des tâches d&amp;rsquo;administration système extrêmement complexes et à grande échelle dans des environnements d&amp;rsquo;entreprise.&lt;/p>
&lt;p>Cet article explique très en détail l&amp;rsquo;architecture spécifique, les méthodes d&amp;rsquo;implémentation et les meilleures pratiques de gestion de la mémoire et de conversion de chaînes de caractères pour une intégration bidirectionnelle entre PowerShell et C++.&lt;/p>
&lt;h2 id="pourquoi-intégrer-powershell-et-c-">Pourquoi intégrer PowerShell et C++ ?
&lt;/h2>&lt;h3 id="1-dépasser-les-limites-de-performances">1. Dépasser les limites de performances
&lt;/h3>&lt;p>PowerShell possède des éléments de langage interprété et à typage dynamique exécutés sur le .NET Framework (ou .NET Core / .NET). Par conséquent, lors du traitement massif de texte, du chiffrement complexe ou de l&amp;rsquo;analyse de journaux d&amp;rsquo;événements comptant des millions de lignes, la vitesse d&amp;rsquo;exécution et la consommation de mémoire peuvent devenir des goulots d&amp;rsquo;étranglement.&lt;/p>
&lt;p>Considérons un modèle de complexité de calcul et de temps de traitement. Si le temps de traitement total de la tâche est $T_{total}$, le temps de traitement avec PowerShell seul et le temps de traitement lorsqu&amp;rsquo;il est déchargé sur C++ peuvent être formulés comme suit :&lt;/p>
$$ T_{total}^{(PS)} = N \times (t_{overhead} + t_{compute}^{(PS)}) $$$$ T_{total}^{(C++)} = t_{interop} + N \times t_{compute}^{(C++)} $$&lt;p>Ici, $N$ est le nombre d&amp;rsquo;éléments à traiter, $t_{overhead}$ est la surcharge associée au traitement des boucles de PowerShell, $t_{compute}$ est le temps de calcul pur par élément, et $t_{interop}$ est la surcharge des appels aux limites via P/Invoke, etc.&lt;/p>
&lt;p>Lorsque $N$ est suffisamment grand, puisque $t_{overhead} \gg 0$ et $t_{compute}^{(PS)} > t_{compute}^{(C++)}$, il est bien plus efficace de déléguer (décharger) le traitement à C++, même en payant le $t_{interop}$ initial, car la latence globale diminuera considérablement.&lt;/p>
&lt;h3 id="2-accès-à-lapi-native-win32">2. Accès à l&amp;rsquo;API native Win32
&lt;/h3>&lt;p>Bien qu&amp;rsquo;il soit possible d&amp;rsquo;appeler l&amp;rsquo;API Win32 via C# en utilisant &lt;code>Add-Type&lt;/code> dans PowerShell, il est extrêmement difficile de définir directement en C# / PowerShell des API impliquant des structures complexes ou des fonctions de rappel (ex : contrôle du pilote de mini-filtre, opérations avancées sur la mémoire des processus). En créant une DLL native enveloppée en C++ et en l&amp;rsquo;appelant depuis PowerShell, un contrôle système sûr et sécurisé quant au typage devient possible.&lt;/p>
&lt;h2 id="appeler-une-dll-native-c-depuis-powershell">Appeler une DLL native C++ depuis PowerShell
&lt;/h2>&lt;p>Le modèle d&amp;rsquo;intégration le plus courant consiste à implémenter des traitements lourds ou spécifiques au système sous forme de DLL C++, puis à les appeler depuis un script PowerShell.&lt;/p>
&lt;h3 id="implémentation-de-la-dll-côté-c-api-win32-et-logique-personnalisée">Implémentation de la DLL côté C++ (API Win32 et logique personnalisée)
&lt;/h3>&lt;p>Tout d&amp;rsquo;abord, créez une DLL C++ avec des fonctions exportées pouvant être appelées depuis PowerShell. Voici un code C++ simple en guise d&amp;rsquo;exemple, supposant une &amp;ldquo;fonction effectuant un chiffrement/déchiffrement de données textuelles à grande échelle ou un calcul de hachage complexe&amp;rdquo;.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// NativeLib.cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;windows.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Spécifier le chaînage C et __stdcall pour faciliter l&amp;#39;appel via P/Invoke
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">extern&lt;/span> &lt;span class="s">&amp;#34;C&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">__declspec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dllexport&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="kr">__stdcall&lt;/span> &lt;span class="n">ComputeHeavyTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">multiplier&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">dataSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Simulation intentionnelle d&amp;#39;un traitement lourd
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">dataSize&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">multiplier&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Fonction traitant les chaînes de caractères (utilisation de LPWSTR pour la compatibilité Unicode)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">__declspec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dllexport&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="kr">__stdcall&lt;/span> &lt;span class="n">ProcessSystemString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LPCWSTR&lt;/span> &lt;span class="n">inputString&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">LPWSTR&lt;/span> &lt;span class="n">outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">bufferSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">inputString&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">outputBuffer&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">inputString&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Traitement complexe de la chaîne (ex : ajout d&amp;#39;un identifiant système)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;PROCESSED_&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">bufferSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Prévention des dépassements de tampon
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">wcscpy_s&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bufferSize&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="gestion-de-la-mémoire-et-conversion-de-chaînes-bstr-lpwstr">Gestion de la mémoire et conversion de chaînes (&lt;code>BSTR&lt;/code>, &lt;code>LPWSTR&lt;/code>)
&lt;/h3>&lt;p>Lors de l&amp;rsquo;échange de données entre C++ et PowerShell (.NET), les points les plus importants à surveiller sont l&amp;rsquo;&lt;strong>encodage des chaînes&lt;/strong> et la &lt;strong>gestion de la mémoire&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>LPCWSTR&lt;/code> / &lt;code>LPWSTR&lt;/code>&lt;/strong> : Pointeur de chaîne large C/C++ (UTF-16LE). Couramment utilisé dans les fonctions de la série &lt;code>W&lt;/code> de l&amp;rsquo;API Windows. Dans P/Invoke, en spécifiant &lt;code>CharSet = CharSet.Unicode&lt;/code>, il sera automatiquement marshalisé avec &lt;code>String&lt;/code> et &lt;code>StringBuilder&lt;/code> de .NET.&lt;/li>
&lt;li>&lt;strong>&lt;code>BSTR&lt;/code>&lt;/strong> : Chaîne large préfixée par sa longueur utilisée dans COM (Component Object Model). La mémoire doit être gérée via &lt;code>SysAllocString&lt;/code> et &lt;code>SysFreeString&lt;/code>. Dans P/Invoke, vous spécifiez &lt;code>[MarshalAs(UnmanagedType.BStr)]&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Lorsque vous allouez de la nouvelle mémoire côté C++ et que vous la renvoyez à PowerShell, la question de savoir qui libère la mémoire (propriété) se pose. La fonction &lt;code>ProcessSystemString&lt;/code> ci-dessus adopte le modèle standard de l&amp;rsquo;API Win32 selon lequel &amp;ldquo;le C++ écrit le résultat dans un tampon (&lt;code>outputBuffer&lt;/code>) alloué au préalable par l&amp;rsquo;appelant (PowerShell)&amp;rdquo;. Cela permet de prévenir les fuites de mémoire.&lt;/p>
&lt;h3 id="add-type-et-pinvoke-côté-powershell">&lt;code>Add-Type&lt;/code> et P/Invoke côté PowerShell
&lt;/h3>&lt;p>Une fois la DLL C++ (&lt;code>NativeLib.dll&lt;/code>) compilée, appelez-la depuis un script PowerShell. Vous compilez et utilisez dynamiquement la signature P/Invoke C# via &lt;code>Add-Type&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># PowerShell Script: Invoke-NativeDLL.ps1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$signature&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="sh">@&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System.Runtime.InteropServices;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System.Text;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">public class NativeInterop
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">{
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> // Définition de ComputeHeavyTask en C++
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> [DllImport(&amp;#34;NativeLib.dll&amp;#34;, CallingConvention = CallingConvention.StdCall)]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> public static extern int ComputeHeavyTask(int multiplier, int dataSize);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> // Définition de ProcessSystemString en C++
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> [DllImport(&amp;#34;NativeLib.dll&amp;#34;, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> public static extern bool ProcessSystemString(string inputString, StringBuilder outputBuffer, int bufferSize);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">}
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;#39;@&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Compilation et ajout du code C# à la session PowerShell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Add-Type&lt;/span> &lt;span class="n">-TypeDefinition&lt;/span> &lt;span class="nv">$signature&lt;/span> &lt;span class="n">-PassThru&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Out-Null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. Appel du calcul numérique lourd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">NativeInterop&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">ComputeHeavyTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">7&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">100000000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Compute Task Result: &lt;/span>&lt;span class="nv">$result&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 2. Appel du traitement de chaîne&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$input&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;SYSTEM_NODE_001&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$bufferSize&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mf">256&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Utilisation de StringBuilder comme tampon pour l&amp;#39;écriture côté C++&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$outputBuffer&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-Object&lt;/span> &lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">StringBuilder&lt;/span> &lt;span class="n">-ArgumentList&lt;/span> &lt;span class="nv">$bufferSize&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$success&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">NativeInterop&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">ProcessSystemString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nv">$input&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$bufferSize&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$success&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Processed String: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$outputBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;String processing failed.&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="visualisation-de-larchitecture">Visualisation de l&amp;rsquo;architecture
&lt;/h3>&lt;p>Le diagramme de séquence suivant illustre le flux d&amp;rsquo;appels et l&amp;rsquo;échange de mémoire entre le script PowerShell et la DLL C++.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant PS as &amp;#34;Script PowerShell&amp;#34;
participant CLR as &amp;#34;.NET CLR (P/Invoke)&amp;#34;
participant CPP as &amp;#34;DLL Native C++&amp;#34;
PS-&amp;gt;&amp;gt;CLR: &amp;#34;Appeler ProcessSystemString&amp;#34;
note right of CLR: &amp;#34;Marshaliser System.String en LPCWSTR&amp;#34;
note right of CLR: &amp;#34;Passer la référence de StringBuilder&amp;#34;
CLR-&amp;gt;&amp;gt;CPP: &amp;#34;ProcessSystemString(LPCWSTR, LPWSTR, int)&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;Exécuter la manipulation de chaîne native&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;Écrire le résultat dans le tampon LPWSTR&amp;#34;
CPP--&amp;gt;&amp;gt;CLR: &amp;#34;retourner bool (Succès)&amp;#34;
note left of CLR: &amp;#34;Lire le tampon StringBuilder modifié&amp;#34;
CLR--&amp;gt;&amp;gt;PS: &amp;#34;Retourner le contrôle d&amp;#39;exécution&amp;#34;
PS-&amp;gt;&amp;gt;PS: &amp;#34;Afficher la chaîne traitée&amp;#34;
&lt;/pre>
&lt;h2 id="appeler-powershell-depuis-c">Appeler PowerShell depuis C++
&lt;/h2>&lt;p>Maintenant, l&amp;rsquo;approche inverse. Il existe des cas où vous souhaitez exécuter dynamiquement des scripts PowerShell à partir de services système ou d&amp;rsquo;applications de bureau créés en C++ et obtenir leurs résultats. Par exemple, un scénario dans lequel un agent de surveillance en C++ exécute un script de réparation PowerShell lorsqu&amp;rsquo;il détecte une anomalie spécifique.&lt;/p>
&lt;p>Il y a principalement deux approches :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Lancement de processus (&lt;code>CreateProcess&lt;/code> / &lt;code>_popen&lt;/code>)&lt;/strong> : Démarrer &lt;code>powershell.exe&lt;/code> comme un processus indépendant et connecter les entrées/sorties standard par un tube (pipe).&lt;/li>
&lt;li>&lt;strong>API d&amp;rsquo;hébergement PowerShell (via C++/CLI)&lt;/strong> : Héberger l&amp;rsquo;environnement d&amp;rsquo;exécution PowerShell au sein du même processus.&lt;/li>
&lt;/ol>
&lt;p>Cet article décrit la méthode de &lt;strong>CreateProcess avec un pipeline&lt;/strong>, qui est la plus robuste et polyvalente dans la programmation système.&lt;/p>
&lt;h3 id="exécution-avec-createprocess-et-les-tubes-anonymes-anonymous-pipes">Exécution avec CreateProcess et les tubes anonymes (Anonymous Pipes)
&lt;/h3>&lt;p>Le code C++ suivant crée des tubes anonymes, lance &lt;code>powershell.exe&lt;/code> comme processus enfant pour exécuter le script, et lit le résultat depuis la sortie standard.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;windows.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">ExecutePowerShellScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">script&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HANDLE&lt;/span> &lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SECURITY_ATTRIBUTES&lt;/span> &lt;span class="n">sa&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">nLength&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">SECURITY_ATTRIBUTES&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">bInheritHandle&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Permettre l&amp;#39;héritage du handle du tube par le processus enfant
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lpSecurityDescriptor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. Création du tube
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">CreatePipe&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">sa&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s">&amp;#34;Error: CreatePipe failed.&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. Configuration des informations de démarrage du processus enfant (PowerShell)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">STARTUPINFOA&lt;/span> &lt;span class="n">si&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ZeroMemory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">si&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">STARTUPINFOA&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">cb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">STARTUPINFOA&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">dwFlags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">STARTF_USESTDHANDLES&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">STARTF_USESHOWWINDOW&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hStdOutput&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hStdError&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">wShowWindow&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SW_HIDE&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Masquer la fenêtre
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROCESS_INFORMATION&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ZeroMemory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PROCESS_INFORMATION&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Construction de la ligne de commande (Version simplifiée évitant l&amp;#39;encodage Base64 avec la stratégie Bypass)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">cmd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;powershell.exe -NoProfile -NonInteractive -Command &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">script&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">begin&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">end&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push_back&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sc">&amp;#39;\0&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. Création du processus
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">CreateProcessA&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">si&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s">&amp;#34;Error: CreateProcess failed.&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Le tube d&amp;#39;écriture n&amp;#39;est pas nécessaire du côté du processus parent, nous le fermons donc (sinon Read sera bloqué)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. Lecture des résultats
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DWORD&lt;/span> &lt;span class="n">bytesRead&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4096&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ReadFile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buffer&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">bytesRead&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">bytesRead&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">buffer&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">bytesRead&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sc">&amp;#39;\0&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. Nettoyage
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">WaitForSingleObject&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hProcess&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">INFINITE&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hProcess&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hThread&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Commande PowerShell pour obtenir la liste des processus et les trier par utilisation du CPU
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">psCommand&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 | Format-Table Name, CPU, Id&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Executing PowerShell from C++...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ExecutePowerShellScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">psCommand&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Result:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="intégration-du-registre-windows-et-de-powershell">Intégration du registre Windows et de PowerShell
&lt;/h3>&lt;p>Lors de l&amp;rsquo;exécution de scripts depuis C++, il faut éviter de coder en dur les valeurs de configuration dynamiques ou les chemins d&amp;rsquo;exécution. Dans la plupart des cas, les applications C++ lisent la configuration depuis le &lt;strong>registre Windows&lt;/strong>.&lt;/p>
&lt;p>Dans les systèmes d&amp;rsquo;entreprise, on préfère une architecture où le côté C++ utilise &lt;code>RegOpenKeyEx&lt;/code> et &lt;code>RegQueryValueEx&lt;/code> pour récupérer le chemin du script PowerShell depuis &lt;code>HKLM\SOFTWARE\MyApp&lt;/code>, et le transmet en tant qu&amp;rsquo;argument au &lt;code>CreateProcess&lt;/code> ci-dessus.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Service Agent C++&amp;#34;] --&amp;gt;|RegQueryValueEx| B[&amp;#34;Registre Windows&amp;#34;]
B --&amp;gt;|Retourner le chemin du script| A
A --&amp;gt;|CreateProcess| C[&amp;#34;powershell.exe&amp;#34;]
C --&amp;gt;|Exécuter| D[&amp;#34;Script d&amp;#39;administration (ex : Restart-Service)&amp;#34;]
D --&amp;gt;|stdout via Tube| C
C --&amp;gt;|ReadFile| A
A --&amp;gt;|Journaliser| E[&amp;#34;Observateur d&amp;#39;événements / Fichier journal&amp;#34;]
&lt;/pre>
&lt;h2 id="analyse-des-performances-et-avantages-du-déchargement-offloading">Analyse des performances et avantages du déchargement (offloading)
&lt;/h2>&lt;p>Pourquoi adopter une architecture aussi complexe ? Comme scénario spécifique, considérons « l&amp;rsquo;analyse de journaux IIS personnalisés de plusieurs gigaoctets ».&lt;/p>
&lt;p>En utilisant &lt;code>Get-Content&lt;/code> dans PowerShell et en analysant ligne par ligne avec des expressions régulières, une quantité massive de temps CPU est consommée en raison de la surcharge liée à la création d&amp;rsquo;objets et au ramasse-miettes (Garbage Collection, GC).&lt;/p>
&lt;p>Le nombre d&amp;rsquo;allocations de mémoire $A$ et le nombre de déclenchements du GC $G$ sont proportionnels à l&amp;rsquo;exécution du script comme suit :&lt;/p>
$$ G \propto \sum_{i=1}^{N} A_i $$&lt;p>Lorsque le traitement est transféré au code natif C++, il est possible d&amp;rsquo;utiliser le mappage de mémoire (&lt;code>CreateFileMapping&lt;/code>, &lt;code>MapViewOfFile&lt;/code>) pour déployer l&amp;rsquo;intégralité du fichier directement en mémoire, et d&amp;rsquo;effectuer des recherches de chaînes sans copie (Zero-copy) via l&amp;rsquo;arithmétique des pointeurs. Dans ce cas, la surcharge associée à la création d&amp;rsquo;objets devient pratiquement nulle, et l&amp;rsquo;analyse s&amp;rsquo;achève à une vitesse proche de la limite théorique de la bande passante de la mémoire.&lt;/p>
&lt;p>En ne renvoyant que les résultats de l&amp;rsquo;analyse (ex : liste des adresses IP aux accès non autorisés) côté PowerShell, le coût de marshaling de P/Invoke peut également être minimisé.&lt;/p>
&lt;h2 id="scénarios-pratiques-dautomatisation-de-ladministration-système">Scénarios pratiques d&amp;rsquo;automatisation de l&amp;rsquo;administration système
&lt;/h2>&lt;h3 id="scénario-1--analyse-rapide-du-système-de-fichiers-et-modification-des-autorisations">Scénario 1 : Analyse rapide du système de fichiers et modification des autorisations
&lt;/h3>&lt;p>Sur un serveur de fichiers à grande échelle, tâche consistant à extraire les fichiers avec une extension spécifique et pour lesquels une liste de contrôle d&amp;rsquo;accès (ACL) particulière est définie, puis à modifier les autorisations par lots.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Rôle de C++&lt;/strong> : Traverser l&amp;rsquo;arborescence des répertoires de manière ultra-rapide en utilisant &lt;code>FindFirstFile&lt;/code> / &lt;code>FindNextFile&lt;/code> et le multi-threading, et générer une liste de chemins de fichiers correspondant aux conditions.&lt;/li>
&lt;li>&lt;strong>Rôle de PowerShell&lt;/strong> : Pour la liste reçue de C++, appliquer les autorisations par lots (ou un traitement lié à Active Directory) en utilisant &lt;code>Set-Acl&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h3 id="scénario-2--collecte-dinformations-matérielles-personnalisées">Scénario 2 : Collecte d&amp;rsquo;informations matérielles personnalisées
&lt;/h3>&lt;p>Surveiller les informations de périphériques matériels propriétaires (ex : cartes PCIe spéciales ou capteurs) qui ne peuvent pas être acquises via WMI (Windows Management Instrumentation) ou CIM (Common Information Model).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Rôle de C++&lt;/strong> : Une DLL qui effectue un appel &lt;code>DeviceIoControl&lt;/code> vers le pilote du périphérique pour récupérer et analyser les données binaires.&lt;/li>
&lt;li>&lt;strong>Rôle de PowerShell&lt;/strong> : Appeler régulièrement la DLL, formater les résultats de l&amp;rsquo;analyse en JSON et les envoyer à l&amp;rsquo;API REST du serveur de surveillance.&lt;/li>
&lt;/ul>
&lt;h2 id="meilleures-pratiques-pour-la-gestion-de-la-mémoire-et-le-dépannage">Meilleures pratiques pour la gestion de la mémoire et le dépannage
&lt;/h2>&lt;p>Les bogues les plus fréquemment rencontrés lors de l&amp;rsquo;intégration sont les &lt;strong>fuites de mémoire&lt;/strong> et les &lt;strong>violations d&amp;rsquo;accès (Access Violation: 0xC0000005)&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Durée de vie des pointeurs&lt;/strong> : Lors de la transmission de &lt;code>[ref]&lt;/code> ou &lt;code>StringBuilder&lt;/code> côté PowerShell, P/Invoke fixe (Pin) cette mémoire uniquement pendant l&amp;rsquo;appel. Vous ne devez pas enregistrer ce pointeur dans une variable globale côté C++ pour y accéder ultérieurement. Si vous effectuez un rappel (callback) asynchrone, vous devez fixer explicitement la mémoire à l&amp;rsquo;aide de &lt;code>GCHandle&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Taille de pointeur dans les environnements 64 bits&lt;/strong> : Le Windows moderne est fondamentalement en 64 bits (x64). La taille du pointeur côté C++ est de 8 octets et vous devez utiliser &lt;code>IntPtr&lt;/code> côté PowerShell (.NET). Étant donné que &lt;code>long&lt;/code> en C++ fait 4 octets sous Windows, un ancien code qui convertit (cast) un pointeur en &lt;code>long&lt;/code> pour le transmettre entraînera un plantage.&lt;/li>
&lt;li>&lt;strong>Inadéquation de l&amp;rsquo;encodage des chaînes&lt;/strong> : PowerShell utilise l&amp;rsquo;UTF-16 en interne. Si vous essayez de les recevoir sous forme de chaînes ANSI (&lt;code>std::string&lt;/code>, &lt;code>char*&lt;/code>) côté C++, les caractères seront déformés. Assurez-vous d&amp;rsquo;utiliser des chaînes larges (&lt;code>std::wstring&lt;/code>, &lt;code>wchar_t*&lt;/code>) et spécifiez &lt;code>CharSet = CharSet.Unicode&lt;/code> également côté P/Invoke.&lt;/li>
&lt;/ol>
&lt;h2 id="conclusion">Conclusion
&lt;/h2>&lt;p>L&amp;rsquo;intégration de PowerShell et C++ est la combinaison ultime qui allie la commodité d&amp;rsquo;un langage de script à la puissance d&amp;rsquo;un langage natif pour automatiser l&amp;rsquo;administration du système.&lt;/p>
&lt;p>En appelant une DLL C++ à l&amp;rsquo;aide de P/Invoke, vous pouvez décharger les tâches gourmandes en calcul et réduire considérablement le temps d&amp;rsquo;exécution. À l&amp;rsquo;inverse, l&amp;rsquo;exploitation des riches modules d&amp;rsquo;administration système de PowerShell par le biais du lancement de processus ou de pipelines à partir d&amp;rsquo;applications C++ permet de réduire significativement les coûts de développement.&lt;/p>
&lt;p>Bien qu&amp;rsquo;il faille prêter attention à la gestion de la mémoire et à la conversion des chaînes aux frontières des langages, la maîtrise des modèles architecturaux et des techniques d&amp;rsquo;implémentation présentés dans cet article vous permettra de concevoir des outils d&amp;rsquo;administration système Windows plus avancés et plus robustes.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Sur ce blog technique, nous continuerons à aborder des sujets approfondis concernant l&amp;rsquo;architecture interne de Windows et l&amp;rsquo;automatisation avancée. Si vous avez des questions ou des commentaires, n&amp;rsquo;hésitez pas à les laisser dans la section des commentaires.&lt;/em>&lt;/p></description></item><item><title>Ce que les ingénieurs doivent faire pour augmenter le trafic mensuel de leur blog technique</title><link>http://kenji.blog/fr/p/tech-blog-growth-strategies-for-engineers/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/tech-blog-growth-strategies-for-engineers/</guid><description>&lt;img src="http://kenji.blog/p/tech-blog-growth-strategies-for-engineers/img/eyecatch.jpg" alt="Featured image of post Ce que les ingénieurs doivent faire pour augmenter le trafic mensuel de leur blog technique" />&lt;h2 id="introduction--le-growth-hacking-des-blogs-techniques-une-compétence-propre-aux-ingénieurs">Introduction : Le Growth Hacking des blogs techniques, une compétence propre aux ingénieurs
&lt;/h2>&lt;p>Beaucoup d&amp;rsquo;ingénieurs logiciels lancent un blog technique, mais rares sont ceux qui parviennent à attirer un certain niveau de trafic et à le maintenir ou l&amp;rsquo;augmenter sur le long terme. Rédiger des articles techniques de haute qualité est une condition préalable, mais l&amp;rsquo;époque où « écrire de bons articles suffisait pour être lu naturellement » est bel et bien révolue. Les algorithmes actuels des moteurs de recherche sont devenus complexes, et le flux d&amp;rsquo;informations sur les réseaux sociaux est plus rapide que jamais.&lt;/p>
&lt;p>Cependant, les ingénieurs possèdent des atouts que d&amp;rsquo;autres professions n&amp;rsquo;ont pas. Ils sont capables de « comprendre l&amp;rsquo;architecture des systèmes, de combiner des outils pour automatiser des processus, et d&amp;rsquo;analyser des données via la programmation ». Dans cet article, au lieu de nous limiter à de simples techniques de rédaction, nous considérerons le blog technique comme un véritable « produit » et expliquerons de manière très détaillée et pratique les stratégies permettant d&amp;rsquo;augmenter drastiquement le trafic mensuel grâce au pouvoir de l&amp;rsquo;ingénierie.&lt;/p>
&lt;hr>
&lt;h2 id="1-architecture-seo-pour-les-blogs-techniques-à-lattention-des-ingénieurs">1. Architecture SEO pour les blogs techniques à l&amp;rsquo;attention des ingénieurs
&lt;/h2>&lt;p>Le système de base du blog (comme les générateurs de sites statiques) et la structure HTML sont les éléments les plus cruciaux pour que les moteurs de recherche puissent interpréter correctement le contenu.&lt;/p>
&lt;h3 id="11-optimisation-des-signaux-web-essentiels-core-web-vitals">1.1 Optimisation des Signaux Web Essentiels (Core Web Vitals)
&lt;/h3>&lt;p>Google utilise l&amp;rsquo;expérience sur la page comme facteur de classement, et les &lt;strong>Signaux Web Essentiels (LCP, FID/INP, CLS)&lt;/strong> ne peuvent être ignorés, même pour un blog technique.
Les blogs techniques utilisent souvent de nombreux blocs de code source, des formules mathématiques (MathJax / KaTeX) et des illustrations. Ces éléments ont tendance à retarder le rendu de la page.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LCP (Largest Contentful Paint)&lt;/strong> : Vitesse de chargement du contenu principal dans la ligne de flottaison. Utilisez le WebP ou l&amp;rsquo;AVIF pour les images à la une, et préchargez-les en ajoutant l&amp;rsquo;attribut &lt;code>fetchpriority=&amp;quot;high&amp;quot;&lt;/code>. De plus, les gros fichiers CSS ou JS pour la coloration syntaxique doivent être chargés de manière asynchrone ou conçus pour n&amp;rsquo;être chargés que sur les pages nécessaires.&lt;/li>
&lt;li>&lt;strong>CLS (Cumulative Layout Shift)&lt;/strong> : Décalage inattendu de la mise en page pendant le chargement de l&amp;rsquo;article. En réservant à l&amp;rsquo;avance l&amp;rsquo;espace d&amp;rsquo;affichage pour les formules et les images à l&amp;rsquo;aide de la propriété CSS &lt;code>aspect-ratio&lt;/code>, etc., vous évitez les sauts visuels lors de l&amp;rsquo;insertion ultérieure de nœuds DOM.&lt;/li>
&lt;li>&lt;strong>INP (Interaction to Next Paint)&lt;/strong> : Réactivité aux interactions de l&amp;rsquo;utilisateur. Il est impératif de ne pas exécuter de JavaScript lourd (par exemple, une recherche plein texte dynamique côté client ou l&amp;rsquo;exécution d&amp;rsquo;un énorme parseur Markdown) sur le thread principal. Il faut le déléguer à un Web Worker ou générer du HTML statique lors du build (SSG).&lt;/li>
&lt;/ul>
&lt;h3 id="12-implémentation-des-données-structurées-json-ld">1.2 Implémentation des données structurées (JSON-LD)
&lt;/h3>&lt;p>Afin d&amp;rsquo;indiquer explicitement aux moteurs de recherche que la page est un « article » et qui en est « l&amp;rsquo;auteur », implémentez des données structurées au format JSON-LD. L&amp;rsquo;utilisation de schémas tels que &lt;code>TechArticle&lt;/code> ou &lt;code>SoftwareSourceCode&lt;/code> augmente la probabilité d&amp;rsquo;apparaître dans les résultats enrichis de Google, ce qui améliore le CTR (taux de clics).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;application/ld+json&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@context&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://schema.org&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;TechArticle&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;headline&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Ce que les ingénieurs doivent faire pour augmenter le trafic mensuel de leur blog technique&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;image&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;https://example.com/img/eyecatch.jpg&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;datePublished&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;2026-09-14T10:00:00+09:00&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;author&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Person&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Kenji&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://example.com/about/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;publisher&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Organization&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Kenji&amp;#39;s Tech Blog&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;logo&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ImageObject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://example.com/img/logo.png&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="13-html-sémantique-et-optimisation-de-la-structure-du-document">1.3 HTML sémantique et optimisation de la structure du document
&lt;/h3>&lt;p>L&amp;rsquo;imbrication correcte des balises d&amp;rsquo;en-tête (&lt;code>h1&lt;/code> à &lt;code>h6&lt;/code>) est fondamentale, mais un blog technique exige également l&amp;rsquo;utilisation précise des balises sémantiques HTML5 telles que &lt;code>article&lt;/code>, &lt;code>section&lt;/code>, &lt;code>aside&lt;/code> et &lt;code>nav&lt;/code>. De plus, l&amp;rsquo;utilisation appropriée des balises &lt;code>&amp;lt;code&amp;gt;&lt;/code> et &lt;code>&amp;lt;pre&amp;gt;&lt;/code> pour le code source, &lt;code>&amp;lt;kbd&amp;gt;&lt;/code> pour les entrées clavier, et &lt;code>&amp;lt;var&amp;gt;&lt;/code> pour les variables permet de fournir un HTML lisible par les machines. Il s&amp;rsquo;agit également d&amp;rsquo;une méthode très efficace pour l&amp;rsquo;indexation de contenu par l&amp;rsquo;IA (collecte de données d&amp;rsquo;apprentissage pour les LLM et systèmes RAG).&lt;/p>
&lt;hr>
&lt;h2 id="2-psychologie-de-lintention-de-recherche-et-stratégie-de-mots-clés">2. Psychologie de l&amp;rsquo;intention de recherche et stratégie de mots-clés
&lt;/h2>&lt;p>Pour maximiser le trafic en provenance des moteurs de recherche (trafic organique), il est nécessaire de déchiffrer avec précision l&amp;rsquo;intention de recherche de l&amp;rsquo;utilisateur, c&amp;rsquo;est-à-dire « pourquoi il a cherché ce mot-clé ». Les intentions de recherche dans le domaine technique peuvent être classées en deux grandes catégories.&lt;/p>
&lt;h3 id="21-type--résolution-derreur--et-type--apprentissage-systématique--revue-">2.1 Type « Résolution d&amp;rsquo;erreur » et Type « Apprentissage systématique / Revue »
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Type Résolution d&amp;rsquo;erreur (Troubleshooting Intent)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Exemples de mots-clés : &lt;code>Docker &amp;quot;no space left on device&amp;quot; solution&lt;/code>, &lt;code>Python IndexError list index out of range cause&lt;/code>&lt;/li>
&lt;li>Psychologie : Bloqué par une erreur lors du développement, l&amp;rsquo;utilisateur cherche un remède immédiat sous forme de commande ou d&amp;rsquo;extrait de code.&lt;/li>
&lt;li>Stratégie : Présentez la « conclusion (code ou commande pour résoudre le problème) » dès le début de l&amp;rsquo;article (dans la ligne de flottaison). Placez le contexte et les explications détaillées des mécanismes plus bas, afin de satisfaire immédiatement le désir de l&amp;rsquo;utilisateur de « réparer tout de suite ». Cela permet de réduire le taux de rebond (bounce rate).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Type Apprentissage systématique / Revue (Learning &amp;amp; Review Intent)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Exemples de mots-clés : &lt;code>React vs Vue 2026 comparaison&lt;/code>, &lt;code>Rust traitement asynchrone introduction&lt;/code>, &lt;code>GCP architecture réseau conception&lt;/code>&lt;/li>
&lt;li>Psychologie : Souhaite sélectionner une nouvelle stack technique ou approfondir sa compréhension depuis les bases, et est prêt à prendre le temps de lire.&lt;/li>
&lt;li>Stratégie : Enrichissez la table des matières (TOC) et utilisez de nombreux schémas et diagrammes d&amp;rsquo;architecture (comme Mermaid). Comparez objectivement les avantages et les inconvénients, et incluez des cas d&amp;rsquo;utilisation pour montrer comment cela s&amp;rsquo;applique dans la pratique, ce qui augmentera le temps passé sur la page.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="22-modèle-de-décroissance-exponentielle-du-trafic-et-stratégie-de-longue-traîne">2.2 Modèle de décroissance exponentielle du trafic et stratégie de longue traîne
&lt;/h3>&lt;p>Le trafic d&amp;rsquo;un article technique a tendance à former un pic (augmentation soudaine) immédiatement après sa publication grâce au buzz sur les réseaux sociaux, puis à diminuer de manière exponentielle. Ce trafic $V(t)$ peut être approximé par le modèle mathématique suivant :&lt;/p>
$$ V(t) = V_0 e^{-\lambda t} + C $$&lt;p>Où :&lt;/p>
&lt;ul>
&lt;li>$V(t)$ : Volume de trafic à l&amp;rsquo;instant $t$&lt;/li>
&lt;li>$V_0$ : Volume du pic de trafic initial dû au buzz sur les réseaux sociaux juste après la publication&lt;/li>
&lt;li>$\lambda$ : Constante d&amp;rsquo;atténuation due à l&amp;rsquo;obsolescence du contenu ou à l&amp;rsquo;oubli sur les réseaux sociaux (dépend de la vitesse d&amp;rsquo;évolution des tendances technologiques)&lt;/li>
&lt;li>$C$ : Trafic organique stable provenant des moteurs de recherche (trafic de base)&lt;/li>
&lt;/ul>
&lt;p>La clé pour augmenter le trafic sur le long terme ne réside pas dans la recherche d&amp;rsquo;un buzz temporaire ($V_0$), mais dans &lt;strong>la façon d&amp;rsquo;augmenter le terme constant $C$ (l&amp;rsquo;afflux continu provenant des moteurs de recherche)&lt;/strong>. En couvrant un grand nombre de « mots-clés de longue traîne » – comme des erreurs spécifiques et de niche ou des méthodes d&amp;rsquo;intégration entre des outils précis – qui ont un faible volume de recherche mais aucune concurrence, vous ferez croître la somme de $C$ pour en faire un volume colossal.&lt;/p>
&lt;hr>
&lt;h2 id="3-analyse-de-contenu-axée-sur-les-données-à-laide-de-lapi-google-search-console">3. Analyse de contenu axée sur les données à l&amp;rsquo;aide de l&amp;rsquo;API Google Search Console
&lt;/h2>&lt;p>Afin de construire une base de trafic stable $C$, il est nécessaire d&amp;rsquo;utiliser les données de la Google Search Console (GSC) et d&amp;rsquo;analyser objectivement « comment vous êtes évalué par Google ». Cependant, cliquer manuellement sur l&amp;rsquo;interface web de GSC a ses limites. En tant qu&amp;rsquo;ingénieur, automatisez l&amp;rsquo;analyse à l&amp;rsquo;aide de l&amp;rsquo;API GSC et de Python.&lt;/p>
&lt;h3 id="31-approche-dautomatisation-avec-lapi-gsc-et-python">3.1 Approche d&amp;rsquo;automatisation avec l&amp;rsquo;API GSC et Python
&lt;/h3>&lt;p>Nous allons créer un script qui détecte automatiquement la manière dont le classement de recherche d&amp;rsquo;un article spécifique baisse avec le temps (Decaying Content), ou les « articles gaspillés » qui ont un nombre élevé d&amp;rsquo;impressions mais un taux de clics (CTR) anormalement bas.
Pour cela, nous utiliserons &lt;code>google-api-python-client&lt;/code> et &lt;code>pandas&lt;/code>.&lt;/p>
&lt;h3 id="32-implémentation-en-python--extraction-automatique-des-contenus-à-faible-ctr">3.2 Implémentation en Python : Extraction automatique des contenus à faible CTR
&lt;/h3>&lt;p>Voici un exemple de script qui récupère les données de performance de recherche des 30 derniers jours via l&amp;rsquo;API, et extrait les « mots-clés et URL d&amp;rsquo;articles ayant une grande marge d&amp;rsquo;amélioration pour le titre ou la description », c&amp;rsquo;est-à-dire ceux dont le nombre d&amp;rsquo;impressions est supérieur ou égal à 1000 et le CTR inférieur ou égal à 2 %.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pandas&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">google.oauth2&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">service_account&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">googleapiclient.discovery&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Authentification et construction du service API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">KEY_FILE_LOCATION&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;path/to/your-service-account-key.json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SCOPES&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;https://www.googleapis.com/auth/webmasters.readonly&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SITE_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://your-tech-blog.com/&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">credentials&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">service_account&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Credentials&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_service_account_file&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">KEY_FILE_LOCATION&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">scopes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">SCOPES&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">webmasters_service&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">build&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;searchconsole&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;v1&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">credentials&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">credentials&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Calcul de la période de requête (30 derniers jours)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">today&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">today&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">end_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">today&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">days&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">start_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">today&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">days&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Exécution de la requête API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">request&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;startDate&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;endDate&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;dimensions&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;query&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;rowLimit&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webmasters_service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">searchanalytics&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">siteUrl&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">SITE_URL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">body&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Traitement des données et filtrage avec Pandas DataFrame&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="s1">&amp;#39;rows&amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rows&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;rows&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">row&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">rows&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Query&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;keys&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;URL&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;keys&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Clicks&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;clicks&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Impressions&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;impressions&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;CTR&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;ctr&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Position&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;position&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Conditions de filtrage : Impressions &amp;gt;= 1000 &amp;amp; CTR &amp;lt; 2%&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;Impressions&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;CTR&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mf">0.02&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Tri croissant par position (priorité aux classements élevés non cliqués)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">target_df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort_values&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;Position&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ascending&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【Liste des recommandations pour améliorer les titres/méta-descriptions】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">target_df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Export CSV si nécessaire&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># target_df.to_csv(&amp;#39;improve_candidates.csv&amp;#39;, index=False)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Aucune donnée trouvée.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En exécutant ce script via des tâches planifiées avec cron ou GitHub Actions, vous pouvez toujours décider de manière axée sur les données « quels titres d&amp;rsquo;articles doivent être réécrits ». Au lieu de se fier à l&amp;rsquo;intuition, une amélioration continue basée sur les données (une sorte de Continuous Content Improvement plutôt que CI/CD) est primordiale.&lt;/p>
&lt;hr>
&lt;h2 id="4-gestion-du-cycle-de-vie-des-articles-et-stratégie-de-réécriture">4. Gestion du cycle de vie des articles et stratégie de réécriture
&lt;/h2>&lt;p>Un article technique ne s&amp;rsquo;arrête pas à sa publication. Avec l&amp;rsquo;évolution des technologies (mise à jour de frameworks, dépréciation d&amp;rsquo;API, etc.), le contenu devient obsolète en un clin d&amp;rsquo;œil. Continuer à fournir des informations obsolètes nuit non seulement à la crédibilité du blog, mais entraîne également une évaluation négative en termes de SEO.&lt;/p>
&lt;h3 id="41-gestion-du-cycle-de-vie-du-contenu-diagramme-de-gantt">4.1 Gestion du cycle de vie du contenu (Diagramme de Gantt)
&lt;/h3>&lt;p>Nous illustrons le cycle de vie idéal pour la gestion du contenu avec un diagramme de Gantt Mermaid.&lt;/p>
&lt;pre class="mermaid">
gantt
title Gestion du cycle de vie du contenu axée sur les données
dateFormat YYYY-MM-DD
axisFormat %m/%d
section &amp;#34;Phase 1 : Planification et Rédaction&amp;#34;
&amp;#34;Analyse des mots-clés et des tendances de recherche&amp;#34; :a1, 2026-09-01, 3d
&amp;#34;Brouillon et validation du code&amp;#34; :a2, after a1, 5d
&amp;#34;Relecture et correction&amp;#34; :a3, after a2, 2d
section &amp;#34;Phase 2 : Publication et Promotion&amp;#34;
&amp;#34;Déploiement via pipeline CI/CD&amp;#34; :p1, 2026-09-11, 1d
&amp;#34;Distribution automatique sur réseaux sociaux (X, LinkedIn, RSS)&amp;#34; :p2, 2026-09-11, 1d
&amp;#34;Propagation vers des services comme Hatena Bookmark&amp;#34; :p3, after p2, 3d
section &amp;#34;Phase 3 : Observation et Analyse&amp;#34;
&amp;#34;Période d&amp;#39;accumulation de données GSC&amp;#34; :m1, 2026-09-14, 28d
&amp;#34;Évaluation des performances via API Python&amp;#34; :m2, after m1, 2d
section &amp;#34;Phase 4 : Amélioration (Réécriture)&amp;#34;
&amp;#34;Correction des titres des articles à faible CTR&amp;#34; :r1, after m2, 3d
&amp;#34;Mise à jour du code vers la dernière version&amp;#34; :r2, after r1, 4d
&lt;/pre>
&lt;p>Ainsi, traiter la création d&amp;rsquo;articles comme un projet de développement logiciel à part entière, et intégrer la phase d&amp;rsquo;exploitation et de maintenance (réécriture) post-publication dans votre planification est le secret pour maintenir et augmenter le trafic.&lt;/p>
&lt;h3 id="42-modèle-mathématique-du-roi-retour-sur-investissement-de-la-création-de-contenu">4.2 Modèle mathématique du ROI (retour sur investissement) de la création de contenu
&lt;/h3>&lt;p>Puisque les ingénieurs consacrent un temps précieux à rédiger des articles, ils doivent être conscients du retour sur investissement (ROI).
Le ROI d&amp;rsquo;un blog peut être formulé de la manière suivante :&lt;/p>
$$ ROI = \frac{\sum_{t=1}^{T} \left( Rev_{ad}(t) + Val_{brand}(t) + Val_{skill}(t) \right) - Cost_{time}}{\text{Cost}_{time}} \times 100 \ (\%) $$&lt;ul>
&lt;li>$T$ : Durée de vie utile de l&amp;rsquo;article (période avant qu&amp;rsquo;il ne devienne obsolète)&lt;/li>
&lt;li>$Rev_{ad}(t)$ : Revenus directs issus de la publicité, de l&amp;rsquo;affiliation ou du sponsoring&lt;/li>
&lt;li>$Val_{brand}(t)$ : Valeur monétaire équivalente de l&amp;rsquo;impact positif sur la carrière en mettant en avant vos compétences techniques (augmentation des offres salariales lors d&amp;rsquo;un changement d&amp;rsquo;emploi, demandes d&amp;rsquo;intervention, etc.)&lt;/li>
&lt;li>$Val_{skill}(t)$ : Valeur de l&amp;rsquo;amélioration de vos propres compétences grâce à l&amp;rsquo;apprentissage et à la recherche effectués pour rédiger l&amp;rsquo;article&lt;/li>
&lt;li>$Cost_{time}$ : Temps consacré à la rédaction de l&amp;rsquo;article, à la création des schémas et à la validation du code (converti à votre taux horaire)&lt;/li>
&lt;/ul>
&lt;p>Le point fort d&amp;rsquo;un blog technique est que même si $Rev_{ad}$ est faible, $Val_{brand}$ et $Val_{skill}$ ont tendance à être extrêmement élevés. En particulier, une explication technique de haute qualité devient directement un portfolio, ce qui s&amp;rsquo;avère redoutablement efficace lors de la recherche d&amp;rsquo;emploi ou de l&amp;rsquo;acquisition de missions en freelance.&lt;/p>
&lt;hr>
&lt;h2 id="5-distribution-via-github-actions-et-lintégration-doutils-dautomatisation-externes">5. Distribution via GitHub Actions et l&amp;rsquo;intégration d&amp;rsquo;outils d&amp;rsquo;automatisation externes
&lt;/h2>&lt;p>Après avoir créé du contenu, le défi est de savoir comment le diffuser efficacement à votre public cible (distribution). Publier manuellement des liens sur chaque réseau social à chaque fois est inefficace et indigne d&amp;rsquo;un ingénieur.&lt;/p>
&lt;h3 id="51-architecture-dautomatisation-du-partage-sur-les-réseaux-sociaux">5.1 Architecture d&amp;rsquo;automatisation du partage sur les réseaux sociaux
&lt;/h3>&lt;p>Nous allons mettre en place une architecture qui automatise l&amp;rsquo;intégralité du processus, de la compilation au déploiement, en passant par la notification sur de multiples plateformes, dès l&amp;rsquo;instant où un fichier Markdown est fusionné dans la branche principale (main) du dépôt GitHub.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Développeur (Git Push)&amp;#34;] --&amp;gt; B[&amp;#34;Dépôt GitHub&amp;#34;]
B --&amp;gt;|Webhook| C[&amp;#34;GitHub Actions (CI/CD)&amp;#34;]
C --&amp;gt;|Build| D[&amp;#34;Générateur de site statique (Hugo/Gatsby)&amp;#34;]
D --&amp;gt;|Déployer| E[&amp;#34;Hébergement (Vercel / Cloudflare Pages)&amp;#34;]
D --&amp;gt;|Générer| F[&amp;#34;Flux RSS (index.xml)&amp;#34;]
F --&amp;gt;|Interrogé par| G[&amp;#34;Zapier / IFTTT / Make&amp;#34;]
G --&amp;gt;|Appel API| H[&amp;#34;Publication auto sur X (Twitter)&amp;#34;]
G --&amp;gt;|Appel API| I[&amp;#34;Publication d&amp;#39;article LinkedIn&amp;#34;]
G --&amp;gt;|Appel API| J[&amp;#34;Webhook de communauté Discord / Slack&amp;#34;]
C --&amp;gt;|Script Actions| K[&amp;#34;API de publication croisée Qiita / Zenn&amp;#34;]
&lt;/pre>
&lt;h3 id="52-points-clés-pour-la-mise-en-place-dun-pipeline-automatisé">5.2 Points clés pour la mise en place d&amp;rsquo;un pipeline automatisé
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Compilation et déploiement via GitHub Actions&lt;/strong>
Si vous utilisez un générateur de site statique, automatisez la génération HTML et le déploiement vers votre hébergeur (Vercel, Netlify, Cloudflare Pages, etc.) à l&amp;rsquo;aide de GitHub Actions. À cette occasion, pour répondre aux exigences des Signaux Web Essentiels mentionnées précédemment, il est également efficace d&amp;rsquo;intégrer un processus d&amp;rsquo;optimisation des images (comme la conversion automatique en WebP) dans le pipeline de compilation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Intégration des réseaux sociaux déclenchée par RSS via Zapier/IFTTT&lt;/strong>
Le générateur de site produit un flux RSS (XML) à jour lors de la compilation. En important cela dans une iPaaS telle que Zapier ou Make (anciennement Integromat), vous pouvez construire un workflow tel que : « Dès qu&amp;rsquo;un nouvel élément est ajouté au RSS, publier le titre et l&amp;rsquo;URL sur X (Twitter) et LinkedIn ». Cela permet de notifier automatiquement vos abonnés à l&amp;rsquo;instant même où l&amp;rsquo;article est publié.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Publication croisée sur Qiita/Zenn (Utilisation de balises canoniques)&lt;/strong>
Tant que l&amp;rsquo;autorité de domaine de votre blog personnel ou d&amp;rsquo;entreprise est faible, il peut être judicieux de tirer parti de la force d&amp;rsquo;attraction de plateformes techniques comme Qiita ou Zenn. Cependant, un simple copier-coller présente le risque de subir des pénalités SEO pour contenu dupliqué.
Ce problème peut être résolu en définissant la &lt;strong>balise Canonical&lt;/strong> dans les métadonnées des articles sur Qiita ou Zenn, en pointant vers l&amp;rsquo;URL de l&amp;rsquo;article original sur votre propre blog. En appelant les API des différentes plateformes depuis GitHub Actions et en écrivant un script pour générer automatiquement l&amp;rsquo;article à partir de votre fichier Markdown, vous pouvez automatiser entièrement la diffusion multicanale.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="conclusion--faire-tourner-le-cycle-de-lamélioration-continue">Conclusion : Faire tourner le cycle de l&amp;rsquo;amélioration continue
&lt;/h2>&lt;p>Pour augmenter drastiquement le trafic mensuel d&amp;rsquo;un blog technique, au-delà de l&amp;rsquo;acte d&amp;rsquo;« écrire », les approches d&amp;rsquo;ingénierie telles que celles présentées ici sont indispensables.&lt;/p>
&lt;ol>
&lt;li>Construction d&amp;rsquo;une architecture de site et d&amp;rsquo;un HTML robustes axés sur le SEO&lt;/li>
&lt;li>Conception d&amp;rsquo;articles prenant en compte l&amp;rsquo;intention de recherche de l&amp;rsquo;utilisateur (résolution d&amp;rsquo;erreur vs apprentissage systématique)&lt;/li>
&lt;li>Analyse de données à l&amp;rsquo;aide de l&amp;rsquo;API Google Search Console et de Python&lt;/li>
&lt;li>Gestion du cycle de vie du contenu et réécriture en tenant compte du ROI&lt;/li>
&lt;li>Automatisation complète de la distribution via le CI/CD et l&amp;rsquo;intégration de Zapier&lt;/li>
&lt;/ol>
&lt;p>Si vous parvenez à assembler ces éléments en un système, votre blog technique deviendra l&amp;rsquo;actif (asset) le plus puissant pour propulser votre propre carrière. Ingénieurs souffrant d&amp;rsquo;une stagnation de trafic, n&amp;rsquo;hésitez pas à commencer le « Growth Hacking de votre blog » dès aujourd&amp;rsquo;hui. Vos compétences en programmation et votre capacité de conception d&amp;rsquo;architecture, cultivées lors de vos activités de développement, seront assurément vos meilleures armes dans la gestion de votre blog.&lt;/p></description></item></channel></rss>