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:
@@ -4,3 +4,4 @@ plan/
|
|||||||
Audit_*/
|
Audit_*/
|
||||||
*.csv
|
*.csv
|
||||||
*.bat
|
*.bat
|
||||||
|
*.log
|
||||||
+122
-9
@@ -3,11 +3,18 @@
|
|||||||
CLI d'export des journaux d'audit pour automates Distech Controls Eclypse.
|
CLI d'export des journaux d'audit pour automates Distech Controls Eclypse.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
AuditLogCLI recupere les journaux d'audit (audit-logs) de chaque automate
|
AuditLogCLI recupere les journaux d'audit de chaque automate Distech
|
||||||
Distech Controls Eclypse liste dans un CSV d'entree, via leur API REST,
|
Controls Eclypse liste dans un CSV d'entree, via leur API REST, et les
|
||||||
et les enregistre au format CSV (un fichier par automate, ou un fichier
|
enregistre au format CSV (un fichier par automate, ou un fichier
|
||||||
consolide unique).
|
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
|
.PARAMETER CsvInput
|
||||||
Chemin vers le fichier CSV d'entree (separateur point-virgule).
|
Chemin vers le fichier CSV d'entree (separateur point-virgule).
|
||||||
Colonnes obligatoires : Hostname, Current Ip, HttpPort, HttpsPort.
|
Colonnes obligatoires : Hostname, Current Ip, HttpPort, HttpsPort.
|
||||||
@@ -46,9 +53,10 @@
|
|||||||
|
|
||||||
.NOTES
|
.NOTES
|
||||||
Prerequis : PowerShell 5.1+ (inclus dans Windows 10/11)
|
Prerequis : PowerShell 5.1+ (inclus dans Windows 10/11)
|
||||||
API : Distech Controls Eclypse REST API v1
|
API : Distech Controls Eclypse REST API v1 (audit-logs) et v2
|
||||||
Securite : TLS 1.2, certificats auto-signes acceptes
|
(package de diagnostic), detection automatique par automate
|
||||||
Important : les noms de query params "startDate"/"endDate" sont une
|
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
|
hypothese non validee contre la documentation officielle de
|
||||||
l'API audit-logs. A verifier avant utilisation en production.
|
l'API audit-logs. A verifier avant utilisation en production.
|
||||||
#>
|
#>
|
||||||
@@ -76,6 +84,8 @@ $ProgressPreference = 'SilentlyContinue'
|
|||||||
# UTILITAIRES
|
# UTILITAIRES
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
|
|
||||||
|
$script:LogFilePath = Join-Path (Get-Location) "AuditLogCLI_$(Get-Date -Format 'yyyy-MM-dd_HH-mm').log"
|
||||||
|
|
||||||
function Write-Log {
|
function Write-Log {
|
||||||
param(
|
param(
|
||||||
[string]$Message,
|
[string]$Message,
|
||||||
@@ -86,6 +96,7 @@ function Write-Log {
|
|||||||
$tag = switch ($Level) { "INFO" {"[INFO ]"} "WARN" {"[WARN ]"} "ERROR" {"[ERR ]"} "OK" {"[ OK ]"} }
|
$tag = switch ($Level) { "INFO" {"[INFO ]"} "WARN" {"[WARN ]"} "ERROR" {"[ERR ]"} "OK" {"[ OK ]"} }
|
||||||
$color = switch ($Level) { "INFO" {"Cyan"} "WARN" {"Yellow"} "ERROR" {"Red"} "OK" {"Green"} }
|
$color = switch ($Level) { "INFO" {"Cyan"} "WARN" {"Yellow"} "ERROR" {"Red"} "OK" {"Green"} }
|
||||||
Write-Host "$ts $tag $Message" -ForegroundColor $color
|
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
|
# VALIDATION DES PARAMETRES DE DATE
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
@@ -290,11 +376,38 @@ foreach ($automate in $automates) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$creds = Get-Credentials -Automate $automate -DefaultUsername $Username -DefaultPassword $Password
|
$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") {
|
if ($OutputFormat -eq "PerAutomate") {
|
||||||
$filePath = Join-Path $outputDir "$ip.csv"
|
$filePath = Join-Path $outputDir "$ip.csv"
|
||||||
|
|||||||
@@ -29,6 +29,15 @@ Se connecte à chaque automate listé dans un CSV, récupère son journal d'audi
|
|||||||
|
|
||||||
Un filtrage optionnel par période (`-StartDate`/`-EndDate`) peut être appliqué à la requête.
|
Un filtrage optionnel par période (`-StartDate`/`-EndDate`) peut être appliqué à la requête.
|
||||||
|
|
||||||
|
### Détection automatique API v1 / v2
|
||||||
|
|
||||||
|
Le script détecte automatiquement la version d'API supportée par chaque automate, sans configuration :
|
||||||
|
|
||||||
|
1. **API v2** (package de diagnostic) est essayée en premier : `GET /api/rest/v2/services/packages/diagnostic`. La réponse est un fichier `.zip` de diagnostic complet, que le script télécharge, extrait, puis analyse pour en extraire les événements de connexion/déconnexion (`connected`/`disconnected`) présents dans `logs/eclypse_*.log` et `logs/karaf.log`. Le fichier zip et les fichiers extraits sont supprimés automatiquement après traitement ; seul le CSV final est conservé.
|
||||||
|
2. En cas d'erreur HTTP sur l'appel v2 (404, 401, 500...), le script bascule automatiquement sur **l'API v1** (`GET /api/rest/v1/system/audit-logs`), qui retourne directement un CSV.
|
||||||
|
|
||||||
|
Le CSV obtenu (v1 ou v2) suit ensuite le même traitement de sortie (`PerAutomate` ou `Consolidated`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Utilisation avec cadMasterCLI
|
## Utilisation avec cadMasterCLI
|
||||||
@@ -216,6 +225,10 @@ Vérifier que les colonnes `HttpPort` et `HttpsPort` du CSV contiennent des vale
|
|||||||
|
|
||||||
Les noms des paramètres de requête (`startDate`/`endDate`) utilisés par ce script sont une hypothèse non validée contre la documentation officielle de l'API `audit-logs`. Si le filtrage ne fonctionne pas, vérifier la documentation de l'API Eclypse de l'automate concerné.
|
Les noms des paramètres de requête (`startDate`/`endDate`) utilisés par ce script sont une hypothèse non validée contre la documentation officielle de l'API `audit-logs`. Si le filtrage ne fonctionne pas, vérifier la documentation de l'API Eclypse de l'automate concerné.
|
||||||
|
|
||||||
|
#### "V2 indisponible, bascule V1" dans les logs
|
||||||
|
|
||||||
|
Message normal (niveau `WARN`) : l'automate ne supporte pas l'API v2 (package de diagnostic), le script utilise donc l'API v1 (`audit-logs`) à la place. Aucune action requise.
|
||||||
|
|
||||||
<!-- EN -->
|
<!-- EN -->
|
||||||
# AuditLogCLI
|
# AuditLogCLI
|
||||||
|
|
||||||
@@ -247,6 +260,15 @@ Connects to each controller listed in a CSV, retrieves its audit log via the RES
|
|||||||
|
|
||||||
An optional date-range filter (`-StartDate`/`-EndDate`) can be applied to the request.
|
An optional date-range filter (`-StartDate`/`-EndDate`) can be applied to the request.
|
||||||
|
|
||||||
|
### Automatic API v1 / v2 detection
|
||||||
|
|
||||||
|
The script automatically detects which API version each controller supports, with no configuration needed:
|
||||||
|
|
||||||
|
1. **API v2** (diagnostic package) is tried first: `GET /api/rest/v2/services/packages/diagnostic`. The response is a full diagnostic `.zip` file, which the script downloads, extracts, then parses to pull out connection/disconnection events (`connected`/`disconnected`) found in `logs/eclypse_*.log` and `logs/karaf.log`. The zip file and extracted files are automatically deleted after processing; only the final CSV is kept.
|
||||||
|
2. On any HTTP error from the v2 call (404, 401, 500...), the script automatically falls back to **API v1** (`GET /api/rest/v1/system/audit-logs`), which returns a CSV directly.
|
||||||
|
|
||||||
|
The resulting CSV (v1 or v2) then goes through the same output handling (`PerAutomate` or `Consolidated`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Using with cadMasterCLI
|
## Using with cadMasterCLI
|
||||||
@@ -435,3 +457,7 @@ Check that the CSV's `HttpPort` and `HttpsPort` columns contain valid values. A
|
|||||||
#### The `-StartDate`/`-EndDate` filter seems to have no effect
|
#### The `-StartDate`/`-EndDate` filter seems to have no effect
|
||||||
|
|
||||||
The query parameter names (`startDate`/`endDate`) used by this script are an unverified assumption against the official `audit-logs` API documentation. If filtering does not work, check the Eclypse API documentation for the specific controller.
|
The query parameter names (`startDate`/`endDate`) used by this script are an unverified assumption against the official `audit-logs` API documentation. If filtering does not work, check the Eclypse API documentation for the specific controller.
|
||||||
|
|
||||||
|
#### "V2 indisponible, bascule V1" in the logs
|
||||||
|
|
||||||
|
Normal message (`WARN` level): the controller does not support the v2 API (diagnostic package), so the script uses the v1 API (`audit-logs`) instead. No action needed.
|
||||||
|
|||||||
Reference in New Issue
Block a user