Files
ECY-Auditlog/AuditLogCLI.ps1
T
cadjou 3ca397d518 Ajout du script AuditLogCLI
- Script principal : AuditLogCLI.ps1 (310 lignes) — conversion PowerShell de auditLog.bat, export des journaux d'audit Distech Eclypse via API REST, compatible cadMasterCLI
- Documentation : README.md (437 lignes) — bilingue FR/EN (<!-- FR -->/<!-- EN -->), compatible affichage cadMasterCLI
2026-07-09 18:00:24 +02:00

311 lines
12 KiB
PowerShell

<#
.SYNOPSIS
CLI d'export des journaux d'audit pour automates Distech Controls Eclypse.
.DESCRIPTION
AuditLogCLI recupere les journaux d'audit (audit-logs) de chaque automate
Distech Controls Eclypse liste dans un CSV d'entree, via leur API REST,
et les enregistre au format CSV (un fichier par automate, ou un fichier
consolide unique).
.PARAMETER CsvInput
Chemin vers le fichier CSV d'entree (separateur point-virgule).
Colonnes obligatoires : Hostname, Current Ip, HttpPort, HttpsPort.
Colonnes optionnelles : Username, Password (surchargent -Username/-Password).
.PARAMETER Username
Nom d'utilisateur pour l'authentification API (defaut: admin).
Peut etre surcharge par la colonne Username du CSV.
.PARAMETER Password
Mot de passe pour l'authentification API (defaut: vide).
Peut etre surcharge par la colonne Password du CSV.
.PARAMETER StartDate
Date de debut (format yyyy-MM-dd) pour filtrer les journaux d'audit. Optionnel.
.PARAMETER EndDate
Date de fin (format yyyy-MM-dd) pour filtrer les journaux d'audit. Optionnel.
.PARAMETER OutputFormat
Format de sortie :
PerAutomate - Un fichier CSV brut par automate, dans un dossier horodate (defaut)
Consolidated - Un seul fichier CSV avec toutes les lignes, colonnes Hostname/IP ajoutees
.EXAMPLE
.\AuditLogCLI.ps1 -CsvInput ".\automates.csv"
Recupere les journaux d'audit de tous les automates listes dans le CSV.
Genere un fichier CSV par automate dans un dossier Audit_yyyy-MM-dd_HH-mm.
.EXAMPLE
.\AuditLogCLI.ps1 -CsvInput ".\automates.csv" -OutputFormat Consolidated -StartDate 2026-01-01 -EndDate 2026-07-09
Recupere les journaux d'audit filtres sur la periode donnee et les
consolide dans un seul fichier CSV.
.NOTES
Prerequis : PowerShell 5.1+ (inclus dans Windows 10/11)
API : Distech Controls Eclypse REST API v1
Securite : TLS 1.2, certificats auto-signes acceptes
Important : les noms de query params "startDate"/"endDate" sont une
hypothese non validee contre la documentation officielle de
l'API audit-logs. A verifier avant utilisation en production.
#>
param(
[Parameter(Mandatory)]
[string]$CsvInput,
[string]$Username = "admin",
[string]$Password = "",
[string]$StartDate,
[string]$EndDate,
[ValidateSet("PerAutomate", "Consolidated")]
[string]$OutputFormat = "PerAutomate"
)
# Performance : desactiver la barre de progression Invoke-WebRequest
$ProgressPreference = 'SilentlyContinue'
# =====================================================================
# UTILITAIRES
# =====================================================================
function Write-Log {
param(
[string]$Message,
[ValidateSet("INFO", "WARN", "ERROR", "OK")]
[string]$Level = "INFO"
)
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$tag = switch ($Level) { "INFO" {"[INFO ]"} "WARN" {"[WARN ]"} "ERROR" {"[ERR ]"} "OK" {"[ OK ]"} }
$color = switch ($Level) { "INFO" {"Cyan"} "WARN" {"Yellow"} "ERROR" {"Red"} "OK" {"Green"} }
Write-Host "$ts $tag $Message" -ForegroundColor $color
}
# =====================================================================
# FONCTION : Initialize-ApiClient
# Force TLS 1.2 et accepte les certificats auto-signes (equivalent curl -k)
# =====================================================================
function Initialize-ApiClient {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) {
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
}
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}
# =====================================================================
# FONCTION : Read-AutomateCsv
# =====================================================================
function Read-AutomateCsv {
param([string]$CsvPath)
if (-not (Test-Path $CsvPath)) {
throw "Fichier CSV introuvable : $CsvPath"
}
$rows = @(Import-Csv -Path $CsvPath -Delimiter ";" -Encoding UTF8)
if ($rows.Count -eq 0) {
throw "Fichier CSV vide : $CsvPath"
}
Write-Log -Message "CSV charge : $($rows.Count) ligne(s) depuis $CsvPath" -Level INFO
return $rows
}
# =====================================================================
# FONCTION : Get-BaseUrl
# HTTPS priorise sur HTTP, automate ignore si aucun port valide
# =====================================================================
function Get-BaseUrl {
param([PSCustomObject]$Automate)
$ip = $Automate."Current Ip"
$httpsPort = $Automate.HttpsPort
$httpPort = $Automate.HttpPort
if ($httpsPort -and $httpsPort -ne "" -and [int]$httpsPort -gt 0 -and [int]$httpsPort -ne -1) {
if ([int]$httpsPort -eq 443) { return "https://$ip" }
return "https://${ip}:$httpsPort"
}
if ($httpPort -and $httpPort -ne "" -and [int]$httpPort -gt 0 -and [int]$httpPort -ne -1) {
if ([int]$httpPort -eq 80) { return "http://$ip" }
return "http://${ip}:$httpPort"
}
return $null
}
# =====================================================================
# FONCTION : Get-Credentials
# Identifiants CSV prioritaires sur les parametres globaux
# =====================================================================
function Get-Credentials {
param(
[PSCustomObject]$Automate,
[string]$DefaultUsername,
[string]$DefaultPassword
)
$username = $DefaultUsername
$password = $DefaultPassword
if ($Automate.Username -and $Automate.Username -ne "") { $username = $Automate.Username }
if ($Automate.Password -and $Automate.Password -ne "") { $password = $Automate.Password }
return @{ Username = $username; Password = $password }
}
function Get-AuthHeader {
param(
[string]$Username,
[AllowEmptyString()][string]$Password
)
$pair = "${Username}:${Password}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
return @{
"Authorization" = "Basic $base64"
"Accept" = "text/csv, application/json, text/plain, */*"
}
}
function Get-AuditLogUrl {
param(
[string]$BaseUrl,
[string]$StartDate,
[string]$EndDate
)
$url = "$BaseUrl/api/rest/v1/system/audit-logs"
$queryParams = @()
if ($StartDate) { $queryParams += "startDate=$StartDate" }
if ($EndDate) { $queryParams += "endDate=$EndDate" }
if ($queryParams.Count -gt 0) { $url += "?" + ($queryParams -join "&") }
return $url
}
function Invoke-AuditLogGet {
param(
[string]$Url,
[string]$Username,
[AllowEmptyString()][string]$Password
)
$headers = Get-AuthHeader -Username $Username -Password $Password
return Invoke-WebRequest -Uri $Url -Method GET -Headers $headers -UseBasicParsing -TimeoutSec 30
}
# =====================================================================
# VALIDATION DES PARAMETRES DE DATE
# =====================================================================
foreach ($dateParam in @(
@{ Name = "StartDate"; Value = $StartDate },
@{ Name = "EndDate"; Value = $EndDate }
)) {
if ($dateParam.Value) {
$parsed = [DateTime]::MinValue
if (-not [DateTime]::TryParseExact($dateParam.Value, "yyyy-MM-dd", $null, [System.Globalization.DateTimeStyles]::None, [ref]$parsed)) {
throw "Parametre -$($dateParam.Name) invalide : '$($dateParam.Value)' (format attendu : yyyy-MM-dd)"
}
}
}
# =====================================================================
# INITIALISATION
# =====================================================================
Initialize-ApiClient
Write-Log -Message "=== AuditLogCLI demarre - OutputFormat: $OutputFormat ===" -Level INFO
$automates = Read-AutomateCsv -CsvPath $CsvInput
$statsTotal = 0
$statsError = 0
$consolidatedRows = @()
$outputDir = $null
if ($OutputFormat -eq "PerAutomate") {
$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm"
$outputDir = Join-Path (Get-Location) "Audit_$timestamp"
New-Item -ItemType Directory -Path $outputDir -Force | Out-Null
Write-Log -Message "Dossier de sortie : $outputDir" -Level INFO
}
# =====================================================================
# TRAITEMENT DE CHAQUE AUTOMATE
# =====================================================================
foreach ($automate in $automates) {
$hostname = $automate.Hostname
$ip = $automate."Current Ip"
$statsTotal++
try {
$baseUrl = Get-BaseUrl -Automate $automate
if (-not $baseUrl) {
Write-Log -Message "[$hostname] Aucun port HTTP/HTTPS valide - ignore" -Level WARN
$statsError++
continue
}
$creds = Get-Credentials -Automate $automate -DefaultUsername $Username -DefaultPassword $Password
$url = Get-AuditLogUrl -BaseUrl $baseUrl -StartDate $StartDate -EndDate $EndDate
Write-Log -Message "[$hostname] GET $url (user: $($creds.Username))" -Level INFO
$response = Invoke-AuditLogGet -Url $url -Username $creds.Username -Password $creds.Password
if ($OutputFormat -eq "PerAutomate") {
$filePath = Join-Path $outputDir "$ip.csv"
Set-Content -Path $filePath -Value $response.Content -Encoding UTF8
Write-Log -Message "[$hostname] Journal d'audit ecrit : $filePath" -Level OK
}
else {
# Suppose une reponse API au format CSV (comme le .bat d'origine qui
# ecrit directement la reponse brute dans un fichier .csv)
$rows = @($response.Content | ConvertFrom-Csv)
foreach ($row in $rows) {
$obj = [ordered]@{ Hostname = $hostname; IP = $ip }
foreach ($prop in $row.PSObject.Properties) { $obj[$prop.Name] = $prop.Value }
$consolidatedRows += [PSCustomObject]$obj
}
Write-Log -Message "[$hostname] $($rows.Count) entree(s) d'audit recuperee(s)" -Level OK
}
}
catch {
Write-Log -Message "[$hostname] ERREUR : $($_.Exception.Message)" -Level ERROR
$statsError++
}
}
# =====================================================================
# ECRITURE DE LA SORTIE CONSOLIDEE
# =====================================================================
if ($OutputFormat -eq "Consolidated") {
$timestamp = Get-Date -Format "yyyy-MM-dd_HHhmm"
$outputFile = Join-Path (Get-Location) "audit_$timestamp.csv"
if ($consolidatedRows.Count -gt 0) {
$consolidatedRows | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8
Write-Log -Message "CSV consolide ecrit : $outputFile ($($consolidatedRows.Count) ligne(s))" -Level OK
}
else {
Write-Log -Message "Aucune donnee a ecrire dans le CSV consolide" -Level WARN
}
}
# =====================================================================
# RESUME FINAL
# =====================================================================
Write-Log -Message "========== RESUME ==========" -Level INFO
Write-Log -Message "Automates traites : $statsTotal" -Level INFO
Write-Log -Message "Automates en erreur : $statsError" -Level $(if ($statsError -gt 0) { "WARN" } else { "INFO" })
Write-Log -Message "============================" -Level INFO