726 lines
28 KiB
PowerShell
726 lines
28 KiB
PowerShell
# Script d'Audit Firewall - Network Reputation Service
|
||
# Auteur: Hubert Cornet
|
||
# Date: 03/09/2025
|
||
# Version: 1.2
|
||
|
||
Clear-Host
|
||
|
||
# Configuration globale
|
||
$ErrorActionPreference = "Continue"
|
||
$WarningPreference = "SilentlyContinue"
|
||
|
||
# Couleurs pour les grades
|
||
$GradeColors = @{
|
||
'A+' = '#28a745'
|
||
'A' = '#52b83a'
|
||
'B+' = '#7ac92e'
|
||
'B' = '#a3da23'
|
||
'C+' = '#cceb17'
|
||
'C' = '#f5f90c'
|
||
'D+' = '#f7d808'
|
||
'D' = '#f9b604'
|
||
'E+' = '#fb9500'
|
||
'E' = '#fd7300'
|
||
'F+' = '#ff5100'
|
||
'F' = '#dc3545'
|
||
}
|
||
|
||
### Functions ###
|
||
|
||
## Function Write-ColorOutput : pour afficher du texte en couleur
|
||
Function Write-ColorOutput {
|
||
Param(
|
||
[string]$Text,
|
||
[string]$Color = "White"
|
||
)
|
||
|
||
Try{
|
||
Write-Host $Text -ForegroundColor $Color
|
||
}
|
||
Catch {
|
||
Write-Host $Text
|
||
}
|
||
}
|
||
|
||
## Function Prerequisites : vérifie les prérequis
|
||
Function Prerequisites {
|
||
Write-ColorOutput "`n === Vérification des prérequis ===" "Cyan"
|
||
|
||
# Vérification du fichier JSON
|
||
$JsonFile = Join-Path $PSScriptRoot "file-nrs.json"
|
||
|
||
If(-not (Test-Path $JsonFile)) {
|
||
Write-ColorOutput "ERREUR: Le fichier 'file-nrs.json' n'existe pas!" "Red"
|
||
Write-ColorOutput "Veuillez télécharger ou créer le fichier depuis:" "Yellow"
|
||
Write-ColorOutput "https://gitea.tips-of-mine.com/Tips-Of-Mine/Powershell/src/branch/main/cybersecurity/Network%20Reputation%20Service/file-nrs.json" "Blue"
|
||
Write-ColorOutput "Le fichier doit être placé dans le même dossier que ce script." "Yellow"
|
||
|
||
Return $false
|
||
}
|
||
|
||
Write-ColorOutput "✓ Fichier 'file-nrs.json' trouvé" "Green"
|
||
|
||
# Vérification/Installation des modules requis
|
||
$RequiredModules = @('PSWriteHTML', 'PSWriteColor')
|
||
|
||
Foreach($Module in $RequiredModules) {
|
||
If(-not (Get-Module -ListAvailable -Name $Module)) {
|
||
Write-ColorOutput "Installation du module $Module..." "Yellow"
|
||
|
||
Try{
|
||
Install-Module -Name $Module -Force -Scope CurrentUser -AllowClobber
|
||
|
||
Write-ColorOutput "✓ Module $Module installé" "Green"
|
||
}
|
||
Catch {
|
||
Write-ColorOutput "ERREUR: Impossible d'installer le module $Module : $($_.Exception.Message)" "Red"
|
||
|
||
Return $false
|
||
}
|
||
}
|
||
Else {
|
||
Write-ColorOutput "✓ Module $Module disponible" "Green"
|
||
}
|
||
|
||
Import-Module $Module -Force
|
||
}
|
||
|
||
Return $True
|
||
}
|
||
|
||
## Function Check-Categories : pour tester les catégories et URLs
|
||
Function Check-Categories {
|
||
Param(
|
||
[array]$Categories,
|
||
[string]$ProxyUrl = "",
|
||
[System.Management.Automation.PSCredential]$ProxyCredential = $null,
|
||
[int]$TimeoutSeconds = 10
|
||
)
|
||
|
||
$AllResults = @()
|
||
$CategoryCount = 0
|
||
|
||
$BlockKeywors = @("site bloqué", "access denied", "filtrage web", "Access Denied", "Site Blocked") # Définir les mots-clés des page des blocage
|
||
|
||
Foreach($Category in $Categories.Categorie) {
|
||
$CategoryCount++
|
||
|
||
Show-ProgressBar -Id 1 -Current $CategoryCount -Total $Categories.Categorie.Count -Activity "Test des catégories" -Status "Catégorie: $($category.Categorie.nom)"
|
||
|
||
Write-ColorOutput "`n === Test de la catégorie: $($Category.nom) ===" "Cyan"
|
||
#Write-ColorOutput "`nDescription: $($Category.description)" "Gray"
|
||
|
||
$CategoryResults = @()
|
||
$UrlCount = 0
|
||
|
||
Foreach($UrlObj in $Category.urls) {
|
||
$UrlCount++
|
||
|
||
Show-ProgressBar -Id 2 -Current $UrlCount -Total $Category.urls.Count -Activity "Test des URLs de '$($Category.nom)'" -Status $UrlObj.url
|
||
|
||
Write-ColorOutput "Test de: $($UrlObj.url)" "Yellow"
|
||
|
||
#$Result = Get-UrlStatus -Url $UrlObj.url -ProxyUrl $ProxyUrl -ProxyCredential $ProxyCredential -TimeoutSeconds $TimeoutSeconds -BlockPageKeywords $BlockPageKeywords
|
||
|
||
$Result = Get-UrlStatus $UrlObj.url $UrlObj.expected_action $BlockPageKeywords
|
||
|
||
$TestResult = [PSCustomObject]@{
|
||
Category = $category.nom
|
||
CategoryId = $category.id
|
||
Url = $urlObj.url
|
||
Reputation = $urlObj.reputation
|
||
ExpectedAction = $urlObj.expected_action
|
||
Status = $result.ActualResult
|
||
StatusCode = $result.StatusCode
|
||
ResponseTime = $result.ResponseTime
|
||
Error = $result.Details
|
||
Score = $result.Score
|
||
IsCorrect = (($TestResult.Status -eq "Bloqué" -and $UrlObj.expected_action -eq "block") -or ($TestResult.Status -eq "Autorisé" -and $UrlObj.expected_action -eq "allow"))
|
||
}
|
||
|
||
$StatusColor = If($TestResult.IsCorrect) { "Green" } Else { "Red" }
|
||
Write-ColorOutput " → Résultat: $($TestResult.Status) | Attendu: $($TestResult.ExpectedAction) | Correct: $($TestResult.IsCorrect)" $statusColor
|
||
|
||
$CategoryResults += $TestResult
|
||
$AllResults += $TestResult
|
||
}
|
||
|
||
$CategoryScore = Calculate-CategoryScore -Results $CategoryResults
|
||
$CategoryGrade = Convert-ScoreToGrade -Score $CategoryScore
|
||
|
||
Write-ColorOutput "Score de la catégorie '$($Category.nom)': $CategoryScore% (Note: $CategoryGrade)" "Magenta"
|
||
}
|
||
|
||
Write-Progress -Id 1 -Activity "Test des catégories" -Completed
|
||
Write-Progress -Id 2 -Activity "Test des URLs" -Completed
|
||
|
||
return $AllResults
|
||
}
|
||
|
||
## Function Show-ProgressBar : affiche une barre de progression
|
||
Function Show-ProgressBar {
|
||
Param(
|
||
[int]$Current,
|
||
[int]$Total,
|
||
[int]$Id,
|
||
[string]$Activity,
|
||
[string]$Status = ""
|
||
)
|
||
|
||
$Percent = [math]::Round(($Current / $Total) * 100, 1)
|
||
|
||
Write-Progress -Id $Id -Activity $Activity -Status "$Status ($Current/$Total)" -PercentComplete $Percent
|
||
}
|
||
|
||
## FunctionCalculate-CategoryScore : calcule le score d'une catégorie
|
||
Function Calculate-CategoryScore {
|
||
Param(
|
||
[array]$Results
|
||
)
|
||
|
||
$TotalUrls = $Results.Count
|
||
$CorrectResults = 0
|
||
|
||
Foreach($Result in $Results) {
|
||
$IsBlocked = $Result.Status -eq "Bloqué"
|
||
$ShouldBeBlocked = $result.ExpectedAction -eq "block"
|
||
|
||
If(($IsBlocked -and $ShouldBeBlocked) -or (-not $IsBlocked -and -not $ShouldBeBlocked)) {
|
||
$CorrectResults++
|
||
}
|
||
}
|
||
|
||
If($TotalUrls -eq 0) {
|
||
Return 0
|
||
}
|
||
|
||
Return [math]::Round(($CorrectResults / $TotalUrls) * 100, 2)
|
||
}
|
||
|
||
## Function Convert-ScoreToGrade : convertit un score en une note
|
||
Function Convert-ScoreToGrade {
|
||
Param([double]$Score)
|
||
|
||
switch ($Score) {
|
||
{$_ -ge 95} { return 'A+' }
|
||
{$_ -ge 90} { return 'A' }
|
||
{$_ -ge 85} { return 'B+' }
|
||
{$_ -ge 80} { return 'B' }
|
||
{$_ -ge 75} { return 'C+' }
|
||
{$_ -ge 70} { return 'C' }
|
||
{$_ -ge 65} { return 'D+' }
|
||
{$_ -ge 60} { return 'D' }
|
||
{$_ -ge 55} { return 'E+' }
|
||
{$_ -ge 50} { return 'E' }
|
||
{$_ -ge 45} { return 'F+' }
|
||
default { return 'F' }
|
||
}
|
||
}
|
||
|
||
## Function Get-UrlStatus : teste une URL et détermine si elle est bloquée ou autorisée
|
||
Function Get-UrlStatus {
|
||
Param(
|
||
[string]$Url,
|
||
[string]$ExpectedAction, # 'allow' ou 'block'
|
||
[string[]]$BlockPageKeywords, # Exemple: @("Access Denied", "Site Blocked")
|
||
[string]$ProxyAddress = $null,
|
||
[string]$ProxyUseAuthentication = $null,
|
||
[int]$Timeout = 10
|
||
)
|
||
|
||
$Result = [PSCustomObject]@{
|
||
Url = $Url
|
||
Expected = $ExpectedAction
|
||
ActualResult = "Indéterminé" # Ce qui s'est réellement passé (Bloqué/Autorisé)
|
||
TestStatus = "Échec" # Le statut du test (Conforme/Non Conforme)
|
||
Score = $Null
|
||
StatusCode = ""
|
||
Details = ""
|
||
ResponseTime = ""
|
||
}
|
||
|
||
# Préparation des paramètres pour Invoke-WebRequest (Splatting)
|
||
$IWRParams = @{
|
||
Uri = $Url
|
||
UseBasicParsing = $True
|
||
TimeoutSec = $Timeout
|
||
ErrorAction = 'Stop'
|
||
}
|
||
|
||
$Response = $Null
|
||
|
||
# Ajout des paramètres du proxy s'ils sont fournis
|
||
If(-not [string]::IsNullOrEmpty($ProxyAddress)) {
|
||
$IWRParams.Add('Proxy', $ProxyAddress)
|
||
|
||
If($ProxyUseAuthentication) {
|
||
# Demande les identifiants de manière sécurisée et les ajoute à la commande
|
||
$Creds = Get-Credential -Message "Veuillez saisir les identifiants pour le proxy $ProxyAddress"
|
||
$IWRParams.Add('ProxyCredential', $Creds)
|
||
}
|
||
}
|
||
|
||
# -- Exécution du test --
|
||
Try{
|
||
# Exécution de la requête en utilisant les paramètres définis dans la hashtable
|
||
$Response = Invoke-WebRequest @IWRParams
|
||
|
||
# On vérifie si la réponse contient des mots-clés de la page de blocage
|
||
$KeywordFound = $False
|
||
|
||
Foreach($Keyword in $BlockPageKeywords) {
|
||
If($Response.Content -match $Keyword) {
|
||
$KeywordFound = $True
|
||
|
||
break
|
||
}
|
||
}
|
||
|
||
If($KeywordFound) {
|
||
$Result.ActualResult = "Bloqué"
|
||
$Result.Details = "Page de blocage détectée."
|
||
$Result.StatusCode = $Response.StatusCode
|
||
}
|
||
Else {
|
||
$Result.ActualResult = "Autorisé"
|
||
$Result.Details = "Le site a été atteint sans blocage."
|
||
$Result.StatusCode = $Response.StatusCode
|
||
}
|
||
|
||
}
|
||
Catch [System.Net.WebException] {
|
||
If($_.Exception.Status -eq 'Timeout') {
|
||
$Result.ActualResult = "Bloqué (Timeout)"
|
||
|
||
$Result.Details = "La requête a expiré, indiquant un blocage probable par le pare-feu ou le proxy."
|
||
$Result.StatusCode = $Response.StatusCode
|
||
$Result.ResponseTime = "$Timeout"
|
||
}
|
||
Else {
|
||
# On considère les autres erreurs réseau comme un blocage aussi
|
||
$Result.ActualResult = "Erreur de Connexion"
|
||
$Result.Details = "Impossible de joindre le serveur : $($_.Exception.Status)"
|
||
$Result.StatusCode = $Response.StatusCode
|
||
}
|
||
}
|
||
Catch {
|
||
$Result.ActualResult = "Erreur Script"
|
||
$Result.Details = "Erreur inattendue: $($_.Exception.Message)"
|
||
|
||
# Un test en erreur ne doit pas donner de point
|
||
return $result
|
||
}
|
||
|
||
# Le test est réussi si l'action attendue correspond au résultat réel.
|
||
If(($Result.Expected -eq 'block' -and $Result.ActualResult -eq 'Bloqué') -or ($Result.Expected -eq 'allow' -and $Result.ActualResult -eq 'Autorisé')) {
|
||
$Result.TestStatus = "Conforme"
|
||
$Result.Score = 1 # Le test est un succès !
|
||
$Result.Details += " (Résultat conforme à l'attendu)"
|
||
}
|
||
Else {
|
||
$Result.TestStatus = "Non Conforme"
|
||
$Result.Score = 0 # Le test est un échec !
|
||
$Result.Details += " (Résultat NON CONFORME; Attendu: $($Result.Expected); Obtenu: $($Result.ActualResult))"
|
||
}
|
||
|
||
Return $Result
|
||
}
|
||
|
||
## Function Generate-HtmlReport : génère le rapport HTML
|
||
Function Generate-HtmlReport {
|
||
Param(
|
||
[array]$Results,
|
||
[string]$OutputPath
|
||
)
|
||
|
||
Write-ColorOutput "Génération du rapport HTML..." "Yellow"
|
||
|
||
# Calcul des scores
|
||
$Categories = $Results | Group-Object Category
|
||
$CategoryScores = @()
|
||
|
||
Foreach($Cat in $Categories) {
|
||
$Score = Calculate-CategoryScore -Results $Cat.Group
|
||
$Grade = Convert-ScoreToGrade -Score $Score
|
||
|
||
$CategoryScores += [PSCustomObject]@{
|
||
Category = $Cat.Name
|
||
Score = $Score
|
||
Grade = $Grade
|
||
Color = $GradeColors[$grade]
|
||
TotalUrls = $Cat.Group.Count
|
||
CorrectResults = ($Cat.Group | Where-Object IsCorrect).Count
|
||
Results = $Cat.Group
|
||
}
|
||
}
|
||
|
||
# Score global
|
||
$GlobalScore = Calculate-CategoryScore -Results $Results
|
||
$GlobalGrade = Convert-ScoreToGrade -Score $GlobalScore
|
||
$GlobalColor = $GradeColors[$GlobalGrade]
|
||
|
||
# Génération du HTML
|
||
$HtmlContent = @"
|
||
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Audit Firewall - Network Reputation Service</title>
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f5f5f5; color: #333; line-height: 1.6; }
|
||
.container { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
||
h1 { text-align: center; color: #2c3e50; margin-bottom: 10px; font-size: 2.5em; }
|
||
.subtitle { text-align: center; color: #666; margin-bottom: 30px; font-size: 1.1em; }
|
||
.section { background: white; margin: 20px 0; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
||
.section h2 { color: #2c3e50; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #3498db; }
|
||
|
||
/* Score global */
|
||
.global-score { display: flex; align-items: center; justify-content: center; margin: 30px 0; }
|
||
.score-box { background-color: $globalColor; color: white; width: 150px; height: 150px; border-radius: 15px; display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: 0 4px 15px rgba(0,0,0,0.2); margin-right: 40px; }
|
||
.score-grade { font-size: 3em; font-weight: bold; }
|
||
.score-percent { font-size: 1.5em; margin-top: 5px; }
|
||
.score-label { font-size: 1em; margin-top: 5px; opacity: 0.9; }
|
||
.stats { text-align: left; }
|
||
.stats div { margin: 8px 0; font-size: 1.2em; }
|
||
|
||
/* Tableau des scores */
|
||
table { width: 100%; border-collapse: collapse; margin: 20px 0; }
|
||
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
|
||
th { background-color: #3498db; color: white; font-weight: bold; }
|
||
tr:nth-child(even) { background-color: #f9f9f9; }
|
||
tr:hover { background-color: #e8f4fd; }
|
||
.grade-cell { font-weight: bold; color: white; text-align: center; border-radius: 5px; }
|
||
|
||
/* Catégories en grille */
|
||
.categories-grid { display: flex; flex-wrap: wrap; gap: 20px; margin: 20px 0; }
|
||
.category-item { flex: 1; min-width: 280px; max-width: calc(25% - 15px); background: white; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); overflow: hidden; }
|
||
.category-header { padding: 15px; cursor: pointer; transition: background-color 0.3s; }
|
||
.category-header:hover { background-color: #f8f9fa; }
|
||
.category-title { font-size: 1.2em; font-weight: bold; margin-bottom: 8px; color: #2c3e50; }
|
||
.category-score { display: inline-block; padding: 5px 15px; border-radius: 20px; color: white; font-weight: bold; font-size: 0.9em; }
|
||
.category-content { display: none; padding: 0 15px 15px; }
|
||
.category-content.active { display: block; animation: slideDown 0.3s ease; }
|
||
|
||
/* Animations */
|
||
@keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
|
||
|
||
/* Tables détaillées */
|
||
.detail-table { font-size: 0.9em; }
|
||
.detail-table th { font-size: 0.8em; }
|
||
.correct { background-color: #d4edda !important; color: #155724; }
|
||
.incorrect { background-color: #f8d7da !important; color: #721c24; }
|
||
|
||
/* Barème */
|
||
.grading-scale { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 10px; }
|
||
.grade-item { display: flex; align-items: center; padding: 10px; border-radius: 8px; background-color: #f8f9fa; }
|
||
.grade-badge { width: 40px; height: 40px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; color: white; margin-right: 15px; }
|
||
|
||
/* Responsive */
|
||
@media (max-width: 768px) {
|
||
.global-score { flex-direction: column; }
|
||
.score-box { margin-right: 0; margin-bottom: 20px; }
|
||
.category-item { max-width: 100%; }
|
||
}
|
||
|
||
/* Bouton toggle */
|
||
.toggle-btn { float: right; font-size: 1.2em; transition: transform 0.3s; }
|
||
.toggle-btn.active { transform: rotate(180deg); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>🛡️ Audit Firewall - Network Reputation Service</h1>
|
||
<p class="subtitle">Rapport généré le $(Get-Date -Format 'dd/MM/yyyy à HH:mm')</p>
|
||
|
||
<!-- Résumé Exécutif -->
|
||
<div class="section">
|
||
<h2>📊 Résumé Exécutif</h2>
|
||
<div class="global-score">
|
||
<div class="score-box">
|
||
<div class="score-grade">$globalGrade</div>
|
||
<div class="score-percent">$globalScore%</div>
|
||
<div class="score-label">Score Global</div>
|
||
</div>
|
||
<div class="stats">
|
||
<div><strong>📋 Total des URLs testées :</strong> $($Results.Count)</div>
|
||
<div><strong>✅ URLs correctement filtrées :</strong> $(($Results | Where-Object IsCorrect).Count)</div>
|
||
<div><strong>🎯 Taux de réussite :</strong> $([math]::Round((($Results | Where-Object IsCorrect).Count / $Results.Count) * 100, 2))%</div>
|
||
<div><strong>📅 Date du test :</strong> $(Get-Date -Format 'dd/MM/yyyy HH:mm')</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Scores par Catégorie -->
|
||
<div class="section">
|
||
<h2>📈 Scores par Catégorie</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Catégorie</th>
|
||
<th>Score (%)</th>
|
||
<th>Note</th>
|
||
<th>URLs Totales</th>
|
||
<th>Résultats Corrects</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
"@
|
||
|
||
# Ajout des lignes du tableau
|
||
Foreach($CatScore in $CategoryScores) {
|
||
$HtmlContent += @"
|
||
<tr>
|
||
<td><strong>$($catScore.Category)</strong></td>
|
||
<td>$($catScore.Score)%</td>
|
||
<td><span class="grade-cell" style="background-color: $($catScore.Color); padding: 5px 10px; border-radius: 5px;">$($catScore.Grade)</span></td>
|
||
<td>$($catScore.TotalUrls)</td>
|
||
<td>$($catScore.CorrectResults)</td>
|
||
</tr>
|
||
"@
|
||
}
|
||
|
||
$HtmlContent += @"
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Détail des Tests par Catégorie -->
|
||
<div class="section">
|
||
<h2>🔍 Détail des Tests par Catégorie</h2>
|
||
<div class="categories-grid">
|
||
"@
|
||
|
||
# Ajout des catégories
|
||
$CategoryIndex = 0
|
||
|
||
Foreach($CatScore in $CategoryScores) {
|
||
$CategoryIndex++
|
||
$HtmlContent += @"
|
||
<div class="category-item">
|
||
<div class="category-header" onclick="toggleCategory('cat-$CategoryIndex')">
|
||
<div class="category-title">$($CatScore.Category) <span class="toggle-btn" id="btn-cat-$CategoryIndex">▼</span></div>
|
||
<span class="category-score" style="background-color: $($CatScore.Color);">$($CatScore.Grade) - $($CatScore.Score)%</span>
|
||
</div>
|
||
<div class="category-content" id="cat-$CategoryIndex">
|
||
<table class="detail-table">
|
||
<thead>
|
||
<tr>
|
||
<th>URL</th>
|
||
<th>Réputation</th>
|
||
<th>Action Attendue</th>
|
||
<th>Statut</th>
|
||
<th>Correct</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
"@
|
||
|
||
# Ajout des résultats de chaque URL
|
||
Foreach($Result in $CatScore.Results) {
|
||
$RowClass = if($Result.IsCorrect) { "correct" } else { "incorrect" }
|
||
$CorrectText = if($Result.IsCorrect) { "✅ Oui" } else { "❌ Non" }
|
||
|
||
$HtmlContent += @"
|
||
<tr class="$RowClass">
|
||
<td title="$($Result.Url)">$($result.Url.Substring(0, [Math]::Min(30, $Result.Url.Length)))$(if($Result.Url.Length -gt 30){"..."})</td>
|
||
<td>$($Result.Reputation)</td>
|
||
<td>$($Result.ExpectedAction)</td>
|
||
<td>$($Result.Status)</td>
|
||
<td>$CorrectText</td>
|
||
</tr>
|
||
"@
|
||
}
|
||
|
||
$HtmlContent += @"
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
"@
|
||
}
|
||
|
||
$HtmlContent += @"
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Barème de Notation -->
|
||
<div class="section">
|
||
<h2>📏 Barème de Notation</h2>
|
||
<div class="grading-scale">
|
||
"@
|
||
|
||
# Ajout du barème de notation
|
||
$gradingScale = @(
|
||
@{Grade='A+'; Score='95-100%'; Interpretation='Excellent / Parfait'; Color='#28a745'}
|
||
@{Grade='A'; Score='90-95%'; Interpretation='Très bon niveau de filtrage'; Color='#52b83a'}
|
||
@{Grade='B+'; Score='85-90%'; Interpretation='Très bon'; Color='#7ac92e'}
|
||
@{Grade='B'; Score='80-85%'; Interpretation='Bon, quelques ajustements nécessaires'; Color='#a3da23'}
|
||
@{Grade='C+'; Score='75-80%'; Interpretation='Assez bon'; Color='#cceb17'}
|
||
@{Grade='C'; Score='70-75%'; Interpretation='Moyen, lacunes importantes'; Color='#f5f90c'}
|
||
@{Grade='D+'; Score='65-70%'; Interpretation='Passable'; Color='#f7d808'}
|
||
@{Grade='D'; Score='60-65%'; Interpretation='Faible, filtrage inefficace'; Color='#f9b604'}
|
||
@{Grade='E+'; Score='55-60%'; Interpretation='Très faible'; Color='#fb9500'}
|
||
@{Grade='E'; Score='50-55%'; Interpretation='Insuffisant'; Color='#fd7300'}
|
||
@{Grade='F+'; Score='45-50%'; Interpretation='Critique'; Color='#ff5100'}
|
||
@{Grade='F'; Score='0-45%'; Interpretation='Très faible, action immédiate requise'; Color='#dc3545'}
|
||
)
|
||
|
||
Foreach($GradeInfo in $GradingScale) {
|
||
$HtmlContent += @"
|
||
<div class="grade-item">
|
||
<div class="grade-badge" style="background-color: $($GradeInfo.Color);">$($GradeInfo.Grade)</div>
|
||
<div>
|
||
<strong>$($GradeInfo.Score)</strong><br>
|
||
<span style="color: #666;">$($GradeInfo.Interpretation)</span>
|
||
</div>
|
||
</div>
|
||
"@
|
||
}
|
||
|
||
$HtmlContent += @"
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function toggleCategory(categoryId) {
|
||
const content = document.getElementById(categoryId);
|
||
const btn = document.getElementById('btn-' + categoryId);
|
||
|
||
If(content.classList.contains('active')) {
|
||
content.classList.remove('active');
|
||
btn.classList.remove('active');
|
||
content.style.display = 'none';
|
||
}
|
||
Else {
|
||
content.classList.add('active');
|
||
btn.classList.add('active');
|
||
content.style.display = 'block';
|
||
}
|
||
}
|
||
|
||
// Animation au chargement
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const items = document.querySelectorAll('.category-item');
|
||
items.forEach((item, index) => {
|
||
setTimeout(() => {
|
||
item.style.opacity = '1';
|
||
item.style.transform = 'translateY(0)';
|
||
}, index * 100);
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|
||
"@
|
||
|
||
# Écriture du fichier HTML
|
||
Try{
|
||
$HtmlContent | Out-File -FilePath $OutputPath -Encoding UTF8
|
||
Write-ColorOutput "✓ Rapport généré: $OutputPath" "Green"
|
||
}
|
||
Catch {
|
||
Write-ColorOutput "ERREUR: Impossible de générer le rapport: $($_.Exception.Message)" "Red"
|
||
}
|
||
}
|
||
|
||
## Function Main : fonction principale
|
||
Function Main {
|
||
Write-ColorOutput @"
|
||
╔══════════════════════════════════════════════════════════════════════════════╗
|
||
║ AUDIT FIREWALL - NETWORK REPUTATION SERVICE ║
|
||
║ Version 1.0 ║
|
||
╚══════════════════════════════════════════════════════════════════════════════╝
|
||
"@ "Cyan"
|
||
|
||
# Vérification des prérequis
|
||
If(-not (Prerequisites)) {
|
||
Write-ColorOutput "ERREUR: Les prérequis ne sont pas satisfaits. Arrêt du script." "Red"
|
||
|
||
Return
|
||
}
|
||
|
||
# Chargement du fichier JSON
|
||
Try{
|
||
$JsonFile = Join-Path $PSScriptRoot "file-nrs.json"
|
||
$Categories = Get-Content $JsonFile -Raw -Encoding UTF8 | ConvertFrom-Json
|
||
|
||
Write-ColorOutput "✓ Fichier JSON chargé avec $($Categories.categorie.Count) catégories" "Green"
|
||
}
|
||
Catch {
|
||
Write-ColorOutput "ERREUR: Impossible de charger le fichier JSON: $($_.Exception.Message)" "Red"
|
||
|
||
Return
|
||
}
|
||
|
||
# Création du dossier de sortie
|
||
$ReportDate = Get-Date -Format "dddd dd MMMM yyyy-HH mm"
|
||
$ReportsDir = Join-Path $PSScriptRoot "Rapports"
|
||
$OutputDir = Join-Path $ReportsDir $ReportDate
|
||
|
||
If(-not (Test-Path $ReportsDir)) {
|
||
New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null
|
||
}
|
||
|
||
If(-not (Test-Path $OutputDir)) {
|
||
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
|
||
}
|
||
|
||
Write-ColorOutput "`n Dossier de sortie: $outputDir" "Yellow"
|
||
|
||
# Début des tests
|
||
Write-ColorOutput "`n=== DÉBUT DES TESTS ===" "Green"
|
||
$StartTime = Get-Date
|
||
|
||
$AllResults = Check-Categories -Categories $Categories -ProxyUrl $ProxyUrl -ProxyCredential $ProxyCredential -TimeoutSeconds $TimeoutSeconds -BlockPageKeywords $BlockKeywors
|
||
|
||
$EndTime = Get-Date
|
||
$Duration = $EndTime - $StartTime
|
||
|
||
Write-ColorOutput "`n=== RÉSULTATS FINAUX ===" "Green"
|
||
Write-ColorOutput "`n Temps total d'exécution: $($duration.ToString('hh\:mm\:ss'))" "Yellow"
|
||
Write-ColorOutput "`n Total des URLs testées: $($allResults.Count)" "Yellow"
|
||
|
||
# Calcul du score global
|
||
$GlobalScore = Calculate-CategoryScore -Results $AllResults
|
||
$GlobalGrade = Convert-ScoreToGrade -Score $GlobalScore
|
||
|
||
Write-ColorOutput "`n `n Score global: $GlobalScore% - Note: $GlobalGrade" "Magenta"
|
||
|
||
# Génération du rapport HTML
|
||
$ReportPath = Join-Path $OutputDir "Audit_Firewall_Report.html"
|
||
Generate-HtmlReport -Results $AllResults -OutputPath $ReportPath
|
||
|
||
# Sauvegarde des résultats en JSON
|
||
$JsonResultsPath = Join-Path $outputDir "Results.json"
|
||
$AllResults | ConvertTo-Json -Depth 10 | Out-File -FilePath $JsonResultsPath -Encoding UTF8
|
||
Write-ColorOutput "✓ Résultats sauvegardés: $JsonResultsPath" "Green"
|
||
|
||
Write-ColorOutput "`n=== AUDIT TERMINÉ ===" "Green"
|
||
Write-ColorOutput "`n Rapport disponible à: $ReportPath" "Cyan"
|
||
|
||
# Ouverture automatique du rapport
|
||
If(Get-Command "Start-Process" -ErrorAction SilentlyContinue) {
|
||
$OpenReport = Read-Host "`n Voulez-vous ouvrir le rapport maintenant? (O/N)"
|
||
If($OpenReport -eq "O" -or $OpenReport -eq "o" -or $OpenReport -eq "Y" -or $OpenReport -eq "y") {
|
||
Start-Process $ReportPath
|
||
}
|
||
}
|
||
}
|
||
|
||
### Main
|
||
|
||
Clear-Host
|
||
|
||
# Exécution du script principal
|
||
Try{
|
||
Main
|
||
}
|
||
Catch {
|
||
Write-ColorOutput "ERREUR FATALE: $($_.Exception.Message)" "Red"
|
||
Write-ColorOutput "Stack Trace: $($_.ScriptStackTrace)" "Red"
|
||
}
|
||
|