Ajout du support API v2 (package de diagnostic) et du log fichier

- AuditLogCLI.ps1 : detection auto V1/V2 avec fallback sur erreur HTTP
- Téléchargement/extraction du zip de diagnostic
- Extraction des événements connexion/déconnexion (logs eclypse_*.log et karaf.log)
- Nettoyage automatique des fichiers temporaires
- Écriture d'un fichier .log horodate en complement de la console
- README.md : documentation FR/EN de la détection V1/V2
This commit is contained in:
2026-07-15 10:00:09 +02:00
parent 3025e97263
commit b156b1647f
3 changed files with 150 additions and 10 deletions
+122 -9
View File
@@ -3,11 +3,18 @@
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
AuditLogCLI recupere les journaux d'audit 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).
Detection automatique de la version d'API par automate :
- API v2 (package de diagnostic) essayee en premier. Le zip retourne
est extrait et les evenements connexion/deconnexion (logger
DConnection) des logs eclypse_*.log et karaf.log sont convertis en CSV.
- En cas d'erreur HTTP sur l'appel v2, bascule automatique sur
l'API v1 (audit-logs), qui retourne directement un CSV.
.PARAMETER CsvInput
Chemin vers le fichier CSV d'entree (separateur point-virgule).
Colonnes obligatoires : Hostname, Current Ip, HttpPort, HttpsPort.
@@ -46,9 +53,10 @@
.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
API : Distech Controls Eclypse REST API v1 (audit-logs) et v2
(package de diagnostic), detection automatique par automate
Securite : TLS 1.0/1.1/1.2, certificats auto-signes acceptes
Important : les noms de query params "startDate"/"endDate" (v1) sont une
hypothese non validee contre la documentation officielle de
l'API audit-logs. A verifier avant utilisation en production.
#>
@@ -76,6 +84,8 @@ $ProgressPreference = 'SilentlyContinue'
# UTILITAIRES
# =====================================================================
$script:LogFilePath = Join-Path (Get-Location) "AuditLogCLI_$(Get-Date -Format 'yyyy-MM-dd_HH-mm').log"
function Write-Log {
param(
[string]$Message,
@@ -86,6 +96,7 @@ function Write-Log {
$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
Add-Content -Path $script:LogFilePath -Value "$ts $tag $Message" -Encoding UTF8
}
# =====================================================================
@@ -238,6 +249,81 @@ function Invoke-AuditLogGet {
}
}
# =====================================================================
# FONCTIONS : API v2 (package de diagnostic)
# =====================================================================
function Get-DiagnosticPackageUrl {
param([string]$BaseUrl)
return "$BaseUrl/api/rest/v2/services/packages/diagnostic"
}
function Invoke-DiagnosticGet {
param(
[string]$Url,
[string]$Username,
[AllowEmptyString()][string]$Password
)
$headers = Get-AuthHeader -Username $Username -Password $Password
$zipPath = Join-Path $env:TEMP "AuditLogCLI_diag_$(Get-Random).zip"
Invoke-WebRequest -Uri $Url -Method GET -Headers $headers -UseBasicParsing -TimeoutSec 120 -OutFile $zipPath
return $zipPath
}
function Expand-DiagnosticPackage {
param(
[string]$ZipPath,
[string]$DestinationDir
)
Expand-Archive -Path $ZipPath -DestinationPath $DestinationDir -Force
}
# =====================================================================
# FONCTION : Get-ConnectionEvents
# Extrait les evenements connexion/deconnexion (logger DConnection) des
# logs eclypse_*.log et karaf.log d'un package de diagnostic V2 extrait
# =====================================================================
function Get-ConnectionEvents {
param(
[string]$LogDir,
[string]$StartDate,
[string]$EndDate
)
$logFiles = @(Get-ChildItem -Path $LogDir -Filter "eclypse_*.log" -ErrorAction SilentlyContinue)
$karafLog = @(Get-ChildItem -Path $LogDir -Filter "karaf.log" -ErrorAction SilentlyContinue)
$logFiles += $karafLog
$startDt = if ($StartDate) { [DateTime]::ParseExact($StartDate, "yyyy-MM-dd", $null) } else { $null }
$endDt = if ($EndDate) { [DateTime]::ParseExact($EndDate, "yyyy-MM-dd", $null).AddDays(1) } else { $null }
$events = @()
foreach ($logFile in $logFiles) {
$hits = Select-String -Path $logFile.FullName -Pattern "DConnection.*'(.+?)' (connected|disconnected)"
foreach ($hit in $hits) {
$tsPart = $hit.Line.Split('|')[0].Trim()
$ts = [DateTime]::MinValue
if (-not [DateTime]::TryParseExact($tsPart, "yyyy-MM-ddTHH:mm:ss,fff", $null, [System.Globalization.DateTimeStyles]::None, [ref]$ts)) {
continue
}
if ($startDt -and $ts -lt $startDt) { continue }
if ($endDt -and $ts -ge $endDt) { continue }
$events += [PSCustomObject]@{
Timestamp = $ts
User = $hit.Matches[0].Groups[1].Value
Action = $hit.Matches[0].Groups[2].Value
SourceFile = $logFile.Name
}
}
}
return @($events | Sort-Object Timestamp)
}
function ConvertTo-DiagnosticCsv {
param([array]$Events)
if ($Events.Count -eq 0) { return "" }
return ($Events | ConvertTo-Csv -NoTypeInformation | Out-String)
}
# =====================================================================
# VALIDATION DES PARAMETRES DE DATE
# =====================================================================
@@ -290,11 +376,38 @@ foreach ($automate in $automates) {
}
$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
$content = $null
$isV2 = $false
$diagUrl = Get-DiagnosticPackageUrl -BaseUrl $baseUrl
$zipPath = $null
try {
Write-Log -Message "[$hostname] GET $diagUrl (V2, user: $($creds.Username))" -Level INFO
$zipPath = Invoke-DiagnosticGet -Url $diagUrl -Username $creds.Username -Password $creds.Password
$isV2 = $true
}
catch {
Write-Log -Message "[$hostname] V2 indisponible ($($_.Exception.Message)), bascule V1" -Level WARN
}
$content = Invoke-AuditLogGet -Url $url -Username $creds.Username -Password $creds.Password
if ($isV2) {
$tempDir = Join-Path $env:TEMP "AuditLogCLI_$($ip)_$(Get-Random)"
try {
Expand-DiagnosticPackage -ZipPath $zipPath -DestinationDir $tempDir
$events = Get-ConnectionEvents -LogDir (Join-Path $tempDir "logs") -StartDate $StartDate -EndDate $EndDate
$content = ConvertTo-DiagnosticCsv -Events $events
Write-Log -Message "[$hostname] $($events.Count) evenement(s) connexion/deconnexion extrait(s) (V2)" -Level OK
}
finally {
Remove-Item -Path $zipPath -Force -ErrorAction SilentlyContinue
Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
}
}
else {
$url = Get-AuditLogUrl -BaseUrl $baseUrl -StartDate $StartDate -EndDate $EndDate
Write-Log -Message "[$hostname] GET $url (V1, user: $($creds.Username))" -Level INFO
$content = Invoke-AuditLogGet -Url $url -Username $creds.Username -Password $creds.Password
}
if ($OutputFormat -eq "PerAutomate") {
$filePath = Join-Path $outputDir "$ip.csv"