Chapitre 1614 minDébutant
Exercices corrigés PowerShell et Bash type E6 et E7 SISR
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- traiter un cas complet d'automatisation, comme à l'E6 SISR ;
- analyser une tâche planifiée suspecte, comme à l'E7 ;
- passer d'un langage à l'autre sur les mêmes données.
4 exercices corrigés
Ce chapitre rassemble quatre cas complets, construits comme les situations des épreuves du BTS SIO SISR : un contexte d'entreprise, des documents (un script, une sortie de commande, un journal) et des questions qui demandent d'écrire, de lire, de corriger ou de justifier. Les deux premiers ressemblent à une réalisation de l'E6 (automatiser une tâche d'administration et le montrer), le troisième à un dossier de l'E7 (analyser un incident lié à un script), le quatrième entraîne à passer d'un langage à l'autre. Les méthodes des épreuves sont détaillées dans les cours Épreuve E6 SISR et Épreuve E7 SISR.
Cas 1 : contrôler les sauvegardes de configuration
Chez Sorbier Logistique, chaque serveur Linux envoie chaque nuit vers srv-journaux une archive de sa configuration, accompagnée de son empreinte SHA-256 (chapitre 13). Les archives arrivent dans /srv/sauvegardes/<serveur>/. Antoine Mercier veut être alerté chaque matin si un serveur n'a pas envoyé d'archive récente ou si une archive est corrompue. Moussa Diallo écrit le script suivant.
#!/usr/bin/env bash
# /usr/local/bin/verif-sauvegardes.sh : chaque serveur a-t-il une archive de moins de 26 heures, intacte ?
set -euo pipefail
RACINE=/srv/sauvegardes
MAX_MINUTES=$((26 * 60))
etat=0
for dossier in "$RACINE"/*/; do
serveur=$(basename "$dossier")
derniere=$(find "$dossier" -type f -name '*.tar.gz' -mmin -"$MAX_MINUTES" | sort | tail -n 1)
if [[ -z $derniere ]]; then
echo "CRITIQUE : aucune archive de moins de 26 h pour $serveur"
etat=2
continue
fi
nom=$(basename "$derniere")
if ! (cd "$dossier" && sha256sum -c --quiet "$nom.sha256" > /dev/null 2>&1); then
echo "CRITIQUE : empreinte invalide pour $nom"
etat=2
continue
fi
echo "OK : $serveur ($nom)"
done
exit "$etat"
Exercice 1 sur 4 Cas 1, questions 1 à 4 Réussi À revoir
- Que signifie
-mmin -1560dans la commandefind? Pourquoi 26 heures plutôt que 24 ? - Le 3 novembre 2026 à 7 h, le dossier
/srv/sauvegardes/contient deux sous-dossiers.srv-web/contientsrv-web-config-2026-11-02_0215.tar.gzetsrv-web-config-2026-11-03_0215.tar.gz(chacune avec son.sha256correct), modifiées la veille et le jour même à 2 h 15.srv-journaux/ne contient quesrv-journaux-config-2026-11-01_0215.tar.gz, du 1er novembre à 2 h 15, et son empreinte. Donne exactement ce qu'affiche le script et son code de sortie. - Dans la même situation, quelqu'un a ajouté une ligne à la fin de l'archive du 3 novembre de
srv-webaprès la copie, puis remis sa date de modification à 2 h 15. Qu'affiche le script ? - Écris les deux fichiers d'unités systemd qui lancent ce script chaque jour à 7 h sous le compte
verif(qui a le droit de lire/srv/sauvegardes), et explique comment l'équipe sera prévenue d'un code de sortie 2.
Voir la réponseMasquer la réponse de l'exercice 1
-mmin -1560garde les fichiers modifiés il y a moins de 1560 minutes, soit 26 heures (26 × 60). La sauvegarde tourne vers 2 h 15, avec un décalage aléatoire possible et une durée variable : avec une limite de 24 heures exactes, un contrôle à 7 h pourrait déclarer « trop vieille » une archive arrivée la veille à 2 h 20 si celle du jour a pris du retard. Les deux heures de marge évitent les fausses alertes sans laisser passer une nuit manquée.- Le joker
"$RACINE"/*/parcourt les dossiers dans l'ordre alphabétique :srv-journauxavantsrv-web.
CRITIQUE : aucune archive de moins de 26 h pour srv-journaux
OK : srv-web (srv-web-config-2026-11-03_0215.tar.gz)
Code de sortie 2. L'archive de srv-journaux a 52 h 45 à 7 h le 3 novembre : aucune archive récente. Pour srv-web, celle du 2 novembre a 28 h 45, elle est exclue par -mmin ; seule celle du 3 novembre (4 h 45) reste. Si plusieurs archives étaient retenues, sort | tail -n 1 garderait la plus récente, puisque la date est dans le nom au format aaaa-mm-jj_hhmm, qui se trie comme du texte.
3. La date de modification trompe find, mais pas l'empreinte : sha256sum -c recalcule l'empreinte du fichier et la compare à celle du .sha256.
CRITIQUE : aucune archive de moins de 26 h pour srv-journaux
CRITIQUE : empreinte invalide pour srv-web-config-2026-11-03_0215.tar.gz
Code de sortie 2. Une empreinte stockée avec l'archive ne protège que contre la corruption accidentelle : un attaquant qui peut modifier l'archive peut aussi recalculer le .sha256. Pour une vraie garantie d'intégrité, il faut signer l'empreinte, ou la conserver ailleurs.
4. Les deux unités :
# /etc/systemd/system/verif-sauvegardes.service
[Unit]
Description=Contrôle des sauvegardes de configuration
OnFailure=alerte@%n.service
[Service]
Type=oneshot
User=verif
ExecStart=/usr/local/bin/verif-sauvegardes.sh
# /etc/systemd/system/verif-sauvegardes.timer
[Unit]
Description=Contrôle des sauvegardes chaque matin à 7 h
[Timer]
OnCalendar=*-*-* 07:00:00
Persistent=true
[Install]
WantedBy=timers.target
Avec sudo systemctl daemon-reload puis sudo systemctl enable --now verif-sauvegardes.timer. Un code de sortie différent de 0 met le service en état failed : OnFailure= lance alors l'unité alerte@…, qui envoie un message (par l'API de la messagerie de l'équipe, ou un courriel). La supervision Zabbix peut aussi surveiller l'état de ce service et alerter, ce qui a l'avantage de signaler aussi un timer qui ne tourne plus du tout.
Tu avais trouvé ?
Cas 2 : l'état des serveurs Windows
Avant la réunion mensuelle, Chloé Lambert doit présenter l'état des serveurs Windows. Elle collecte les informations depuis le poste d'administration, et obtient la variable $etat suivante :
| PSComputerName | Build | LibreGo | DernierDemarrage |
|---|---|---|---|
| srv-ad | 26100 | 31 | 15/10/2026 |
| srv-ad2 | 26100 | 12 | 15/10/2026 |
| srv-fichiers | 20348 | 9 | 02/08/2026 |
| srv-gestion | 17763 | 7 | 28/10/2026 |
Les numéros de build correspondent aux versions : 17763 pour Windows Server 2019, 20348 pour Windows Server 2022, 26100 pour Windows Server 2025.
Exercice 2 sur 4 Cas 2, questions 1 à 4 Réussi À revoir
- Écris la commande qui produit
$etaten interrogeant les quatre serveurs en une seule fois. La propriétéBuildNumberde la classe CIMWin32_OperatingSystemdonne le build,LastBootUpTimela date du dernier démarrage. - Écris le pipeline qui affiche les serveurs qui ne sont pas encore en Windows Server 2025. Lesquels affiche-t-il ?
- Le 3 novembre 2026, quels serveurs n'ont pas redémarré depuis plus de 60 jours ? Écris la condition et donne le nombre de jours pour chacun. Pourquoi est-ce un problème ?
- Ajoute au résultat une colonne
Versionlisible (« Windows Server 2025 »…) à l'aide d'une table de hachage, et exporte le tout en CSV pour Excel.
Voir la réponseMasquer la réponse de l'exercice 2
-
$etat = Invoke-Command -ComputerName srv-ad, srv-ad2, srv-fichiers, srv-gestion -ScriptBlock { $os = Get-CimInstance -ClassName Win32_OperatingSystem [pscustomobject]@{ Build = [int]$os.BuildNumber LibreGo = [math]::Round((Get-PSDrive -Name C).Free / 1GB) DernierDemarrage = $os.LastBootUpTime } } | Select-Object PSComputerName, Build, LibreGo, DernierDemarrageBuildNumberest une chaîne : la conversion[int]permet les comparaisons numériques de la suite. Si le domaine applique le modèle en tiers, la commande se lance en deux fois, verssrv-adetsrv-ad2avec le compte de niveau 0, verssrv-fichiersetsrv-gestionavec le compte de niveau 1 (paramètre-Credential), et$etatréunit les deux résultats. -
$etat | Where-Object Build -lt 26100 | Select-Object PSComputerName, Buildsrv-fichiers(20348, Windows Server 2022) etsrv-gestion(17763, Windows Server 2019). -
$reference = [datetime]'2026-11-03' $etat | Where-Object { ($reference - $_.DernierDemarrage.Date).Days -gt 60 }.Dateramène chaque date à minuit, pour compter des jours entiers. Seulsrv-fichiersdépasse 60 jours : du 2 août au 3 novembre, il y a 93 jours (29 jours restants d'août, 30 en septembre, 31 en octobre, 3 en novembre).srv-adetsrv-ad2sont à 19 jours,srv-gestionà 6 jours. Un serveur qui n'a pas redémarré depuis trois mois n'a probablement pas appliqué les mises à jour cumulatives mensuelles, qui demandent un redémarrage : il reste exposé à des failles corrigées depuis. -
$versions = @{ 17763 = 'Windows Server 2019'; 20348 = 'Windows Server 2022'; 26100 = 'Windows Server 2025' } $etat | Select-Object PSComputerName, @{ Name = 'Version'; Expression = { $versions[$_.Build] } }, LibreGo, DernierDemarrage | Export-Csv -Path .\etat-serveurs.csv -Delimiter ';' -NoTypeInformation -Encoding utf8BOMLa clé de la table est un entier : c'est pour cela que
Builda été converti en[int]à la question 1. Avec une chaîne'20348',$versions['20348']ne trouverait rien.utf8BOMsuppose PowerShell 7 ; en 5.1, écrisUTF8.
Tu avais trouvé ?
Cas 3 : une tâche planifiée suspecte
Un lundi matin, la supervision signale une activité réseau inhabituelle de srv-gestion vers une adresse Internet, la nuit précédente. En inspectant le serveur, Moussa trouve une tâche planifiée qu'aucun membre de l'équipe n'a créée, dont voici les caractéristiques :
| Propriété | Valeur |
|---|---|
| Nom | MiseAJourAgent |
| Dossier | \Microsoft\Windows\ |
| Créée le | Dimanche 1er novembre 2026, 03:12 |
| Compte | SYSTEM |
| Déclencheur | Toutes les heures |
| Action | powershell.exe -NoProfile -NonInteractive -WindowStyle Hidden -EncodedCommand JABjAD0A… (une chaîne Base64 de plusieurs milliers de caractères) |
La stratégie d'exécution de srv-gestion est RemoteSigned.
Exercice 3 sur 4 Cas 3, questions 1 à 5 Réussi À revoir
- Relève les éléments de cette tâche qui la rendent suspecte.
- Pourquoi la stratégie d'exécution
RemoteSignedn'a-t-elle pas empêché son exécution ? - Comment lire le contenu de la commande encodée sans l'exécuter ?
- Quels journaux et quels événements consulter pour comprendre ce qui s'est passé ?
- Propose quatre mesures pour éviter qu'un tel scénario se reproduise, ou pour le détecter plus vite.
Voir la réponseMasquer la réponse de l'exercice 3
- Les signes : un nom qui imite une tâche légitime, rangé dans le dossier
\Microsoft\Windows\pour se fondre parmi les tâches du système ; une création à 3 h 12 un dimanche, hors des heures de travail de l'équipe ; le compte SYSTEM, le plus privilégié de la machine ; une exécution toutes les heures, typique d'un mécanisme de persistance qui contacte un serveur de commande ; et une ligne de commande qui se cache : fenêtre masquée (-WindowStyle Hidden), code encodé en Base64 (-EncodedCommand) pour échapper à une lecture rapide. Aucun de ces éléments ne prouve seul une attaque, leur réunion est un indicateur de compromission fort. - La stratégie d'exécution ne contrôle que les fichiers de script. Une commande passée par
-EncodedCommand(ou-Command) n'est pas un fichier : elle n'est pas concernée. Et de toute façon, la stratégie d'exécution n'est pas une barrière de sécurité ; un attaquant qui peut créer une tâche enSYSTEMa déjà des droits d'administrateur sur le serveur. - Le Base64 de
-EncodedCommandencode du texte en UTF-16LE. On le décode dans une variable, sans jamais l'exécuter, de préférence sur une machine d'analyse isolée :
$texte = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($chaine))
$texte | Out-File -FilePath .\commande-decodee.txt
On lit ensuite le fichier : il révèle souvent d'autres couches d'encodage, une adresse de téléchargement, un mécanisme de connexion sortante.
4. Dans l'ordre : le journal Microsoft-Windows-PowerShell/Operational, événement 4104 (le code réellement exécuté par chaque bloc de script, décodé, si la journalisation des blocs de script était activée) ; le journal Sécurité, événement 4698 (création d'une tâche planifiée, avec le compte qui l'a créée) et 4688 (création de processus, avec la ligne de commande si l'audit correspondant est activé), et les ouvertures de session (4624, 4625) autour de 3 h 12 pour trouver le compte utilisé par l'attaquant ; l'historique de la tâche dans le journal Microsoft-Windows-TaskScheduler/Operational ; les journaux du pare-feu pour les connexions sortantes. Avant tout, on isole le serveur du réseau et on préserve les preuves (copie des journaux, image de la machine) : c'est le début de la réponse à incident.
5. Quatre mesures parmi : activer par GPO la journalisation des blocs de script et la transcription sur tous les serveurs, et envoyer les événements au SIEM avec une alerte sur -EncodedCommand et sur l'événement 4698 ; déployer App Control for Business (ou AppLocker), qui place PowerShell en mode de langage restreint pour le code non approuvé ; appliquer le moindre privilège et le modèle en tiers, pour que la compromission d'un compte ne donne pas les droits d'administrateur sur les serveurs ; filtrer les flux sortants des serveurs au pare-feu (un serveur de gestion n'a pas à joindre n'importe quelle adresse Internet) ; signer les scripts légitimes et passer les serveurs en AllSigned pour distinguer les scripts approuvés.
Tu avais trouvé ?
Cas 4 : passer d'un langage à l'autre
Sorbier gère des serveurs Windows et Linux : un technicien doit savoir lire un script dans les deux langages et traduire une commande de l'un à l'autre. Les données sont les fichiers postes.csv du chapitre 8 et auth.log du chapitre 9.
Exercice 4 sur 4 Cas 4, questions 1 à 4 Réussi À revoir
- Traduis en Bash, et donne la sortie :
Import-Csv -Path .\postes.csv -Delimiter ';' |
Where-Object { [int]$_.RAMGo -lt 16 } |
ForEach-Object { "$($_.Nom) : $($_.RAMGo) Go" }
- Traduis en PowerShell, et donne le résultat :
grep -c "Failed password" auth.log - Traduis en PowerShell :
ls -1t /srv/sauvegardes/config/*.tar.gz | head -n 1 - Traduis en Bash :
if (-not (Test-Path -Path '/srv/sauvegardes')) { Write-Error 'Dossier absent'; exit 1 }
Voir la réponseMasquer la réponse de l'exercice 4
-
awk -F';' 'NR > 1 && $4 < 16 { print $1 " : " $4 " Go" }' postes.csvPC-0002 : 8 Go PC-0003 : 8 Go PC-0004 : 4 GoNR > 1joue le rôle de l'en-tête queImport-Csvconsomme lui-même, et$4est la colonneRAMGo. -
(Select-String -Path .\auth.log -Pattern 'Failed password' -SimpleMatch).Count6.
-SimpleMatchcherche le texte tel quel, commegrepavec un motif sans caractère spécial. On peut aussi écrire@(Select-String …).Countpour obtenir 0 plutôt que rien quand aucune ligne ne correspond. -
Get-ChildItem -Path /srv/sauvegardes/config -Filter *.tar.gz -File | Sort-Object LastWriteTime -Descending | Select-Object -First 1ls -1ttrie par date de modification, du plus récent au plus ancien ;head -n 1garde la première ligne. En PowerShell, on trie les objets sur leur propriétéLastWriteTime. La commande PowerShell fonctionne aussi sous Linux avecpwsh. -
if [[ ! -d /srv/sauvegardes ]]; then echo "Dossier absent" >&2 exit 1 fiTest-Pathrépond pour un fichier comme pour un dossier ;-dne répond vrai que pour un dossier, ce qui est ici plus précis (Test-Path -PathType Containeren est l'équivalent exact).Write-Errorécrit sur le flux d'erreur,>&2sur la sortie d'erreur.
Tu avais trouvé ?