Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

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.

bash
#!/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

  1. Que signifie -mmin -1560 dans la commande find ? Pourquoi 26 heures plutôt que 24 ?
  2. Le 3 novembre 2026 à 7 h, le dossier /srv/sauvegardes/ contient deux sous-dossiers. srv-web/ contient srv-web-config-2026-11-02_0215.tar.gz et srv-web-config-2026-11-03_0215.tar.gz (chacune avec son .sha256 correct), modifiées la veille et le jour même à 2 h 15. srv-journaux/ ne contient que srv-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.
  3. Dans la même situation, quelqu'un a ajouté une ligne à la fin de l'archive du 3 novembre de srv-web après la copie, puis remis sa date de modification à 2 h 15. Qu'affiche le script ?
  4. É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
  1. -mmin -1560 garde 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.
  2. Le joker "$RACINE"/*/ parcourt les dossiers dans l'ordre alphabétique : srv-journaux avant srv-web.
text
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.

text
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 :

ini
# /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
ini
# /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 :

PSComputerNameBuildLibreGoDernierDemarrage
srv-ad261003115/10/2026
srv-ad2261001215/10/2026
srv-fichiers20348902/08/2026
srv-gestion17763728/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

  1. Écris la commande qui produit $etat en interrogeant les quatre serveurs en une seule fois. La propriété BuildNumber de la classe CIM Win32_OperatingSystem donne le build, LastBootUpTime la date du dernier démarrage.
  2. Écris le pipeline qui affiche les serveurs qui ne sont pas encore en Windows Server 2025. Lesquels affiche-t-il ?
  3. 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 ?
  4. Ajoute au résultat une colonne Version lisible (« 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
  1. powershell
    $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, DernierDemarrage
    

    BuildNumber est 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, vers srv-ad et srv-ad2 avec le compte de niveau 0, vers srv-fichiers et srv-gestion avec le compte de niveau 1 (paramètre -Credential), et $etat réunit les deux résultats.

  2. powershell
    $etat | Where-Object Build -lt 26100 | Select-Object PSComputerName, Build
    

    srv-fichiers (20348, Windows Server 2022) et srv-gestion (17763, Windows Server 2019).

  3. powershell
    $reference = [datetime]'2026-11-03'
    $etat | Where-Object { ($reference - $_.DernierDemarrage.Date).Days -gt 60 }
    

    .Date ramène chaque date à minuit, pour compter des jours entiers. Seul srv-fichiers dé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-ad et srv-ad2 sont à 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.

  4. powershell
    $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 utf8BOM
    

    La clé de la table est un entier : c'est pour cela que Build a été converti en [int] à la question 1. Avec une chaîne '20348', $versions['20348'] ne trouverait rien. utf8BOM suppose PowerShell 7 ; en 5.1, écris UTF8.

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
NomMiseAJourAgent
Dossier\Microsoft\Windows\
Créée leDimanche 1er novembre 2026, 03:12
CompteSYSTEM
DéclencheurToutes les heures
Actionpowershell.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

  1. Relève les éléments de cette tâche qui la rendent suspecte.
  2. Pourquoi la stratégie d'exécution RemoteSigned n'a-t-elle pas empêché son exécution ?
  3. Comment lire le contenu de la commande encodée sans l'exécuter ?
  4. Quels journaux et quels événements consulter pour comprendre ce qui s'est passé ?
  5. 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
  1. 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.
  2. 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 en SYSTEM a déjà des droits d'administrateur sur le serveur.
  3. Le Base64 de -EncodedCommand encode 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 :
powershell
$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

  1. Traduis en Bash, et donne la sortie :
powershell
Import-Csv -Path .\postes.csv -Delimiter ';' |
    Where-Object { [int]$_.RAMGo -lt 16 } |
    ForEach-Object { "$($_.Nom) : $($_.RAMGo) Go" }
  1. Traduis en PowerShell, et donne le résultat : grep -c "Failed password" auth.log
  2. Traduis en PowerShell : ls -1t /srv/sauvegardes/config/*.tar.gz | head -n 1
  3. 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
  1. bash
    awk -F';' 'NR > 1 && $4 < 16 { print $1 " : " $4 " Go" }' postes.csv
    
    text
    PC-0002 : 8 Go
    PC-0003 : 8 Go
    PC-0004 : 4 Go
    

    NR > 1 joue le rôle de l'en-tête que Import-Csv consomme lui-même, et $4 est la colonne RAMGo.

  2. powershell
    (Select-String -Path .\auth.log -Pattern 'Failed password' -SimpleMatch).Count
    

    6. -SimpleMatch cherche le texte tel quel, comme grep avec un motif sans caractère spécial. On peut aussi écrire @(Select-String …).Count pour obtenir 0 plutôt que rien quand aucune ligne ne correspond.

  3. powershell
    Get-ChildItem -Path /srv/sauvegardes/config -Filter *.tar.gz -File |
        Sort-Object LastWriteTime -Descending | Select-Object -First 1
    

    ls -1t trie par date de modification, du plus récent au plus ancien ; head -n 1 garde la première ligne. En PowerShell, on trie les objets sur leur propriété LastWriteTime. La commande PowerShell fonctionne aussi sous Linux avec pwsh.

  4. bash
    if [[ ! -d /srv/sauvegardes ]]; then
        echo "Dossier absent" >&2
        exit 1
    fi
    

    Test-Path répond pour un fichier comme pour un dossier ; -d ne répond vrai que pour un dossier, ce qui est ici plus précis (Test-Path -PathType Container en est l'équivalent exact). Write-Error écrit sur le flux d'erreur, >&2 sur la sortie d'erreur.

Tu avais trouvé ?

Chapitre terminé !

Fais les 4 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : Aide-mémoire : équivalences PowerShell et BashRevoir le sommaire du cours