From 04b9e4f1d190aa9a366be6dd672c551dda734fbf Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 31 Jul 2026 09:55:47 +0200 Subject: [PATCH] Ajout initial du script IPv6ManagerCLI et de sa documentation" --- .gitignore | 5 + IPv6ManagerCLI.ps1 | 386 +++++++++++++++++++++++++++++++++++++++++ README.md | 421 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 812 insertions(+) create mode 100644 .gitignore create mode 100644 IPv6ManagerCLI.ps1 create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d5946d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +plan/ +.claude +.idea/ +*.csv +*.log diff --git a/IPv6ManagerCLI.ps1 b/IPv6ManagerCLI.ps1 new file mode 100644 index 0000000..e626cb5 --- /dev/null +++ b/IPv6ManagerCLI.ps1 @@ -0,0 +1,386 @@ +<# +.SYNOPSIS + CLI d'activation/desactivation IPv6 pour automates Distech Controls Eclypse Facilities (API v2). + +.DESCRIPTION + IPv6ManagerCLI active ou desactive l'IPv6 sur toutes les interfaces reseau + IPv6-capables (secondary, auxiliary, wireless, bridge, primary...) de chaque + automate Distech Controls Eclypse Facilities liste dans un CSV d'entree. + + Pour chaque automate : + 1. GET /api/rest/v2/services/platform/network/interfaces - recupere la liste des interfaces + 2. Filtre les interfaces possedant une section "ipv6" (peu importe son contenu) + 3. POST /api/rest/v2/services/platform/network/interfaces/{name}/ipv6 avec {"enabled": true|false} + pour chaque interface IPv6-capable detectee + + Compatible uniquement avec les automates Eclypse Facilities supportant l'API v2 + (pas de fallback API v1). + +.PARAMETER Action + Etat IPv6 a appliquer sur toutes les interfaces IPv6-capables detectees : + Enable - Active l'IPv6 + Disable - Desactive l'IPv6 (defaut) + +.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. + +.EXAMPLE + .\IPv6ManagerCLI.ps1 -Action Disable -CsvInput ".\automates.csv" + + Desactive l'IPv6 sur toutes les interfaces IPv6-capables de chaque automate du CSV. + +.EXAMPLE + .\IPv6ManagerCLI.ps1 -Action Enable -CsvInput ".\automates.csv" -Password "MonMotDePasse" + + Active l'IPv6 sur toutes les interfaces IPv6-capables de chaque automate du CSV. + +.NOTES + Prerequis : PowerShell 5.1+ (inclus dans Windows 10/11) + API : Distech Controls Eclypse Facilities REST API v2 uniquement + (platform/network/interfaces) - pas de fallback v1 + Securite : TLS 1.0/1.1/1.2, certificats auto-signes acceptes +#> + +param( + [ValidateSet("Enable", "Disable")] + [string]$Action = "Disable", + + [Parameter(Mandatory)] + [string]$CsvInput, + + [string]$Username = "admin", + + [string]$Password = "" +) + +# Performance : desactiver la barre de progression Invoke-WebRequest +$ProgressPreference = 'SilentlyContinue' + +# ===================================================================== +# UTILITAIRES +# ===================================================================== + +$script:LogFilePath = Join-Path (Get-Location) "IPv6ManagerCLI_$(Get-Date -Format 'yyyy-MM-dd_HH-mm').log" + +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 + Add-Content -Path $script:LogFilePath -Value "$ts $tag $Message" -Encoding UTF8 +} + +# ===================================================================== +# FONCTION : Initialize-ApiClient +# Force TLS 1.2 et accepte les certificats auto-signes (equivalent curl -k) +# ===================================================================== +$script:CurlAvailable = $false + +function Initialize-ApiClient { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls + + 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 + + $script:CurlAvailable = [bool](Get-Command curl.exe -ErrorAction SilentlyContinue) +} + +function Test-SslError { + param([System.Exception]$Exception) + $msg = $Exception.Message + return ($msg -match "SSL" -or $msg -match "TLS" -or $msg -match "confiance" -or $msg -match "trust" -or $msg -match "certificate" -or $msg -match "envoi") +} + +function Invoke-CurlGet { + param( + [string]$Url, + [string]$Username, + [AllowEmptyString()][string]$Password + ) + $output = & curl.exe -s -k -u "${Username}:${Password}" -H "Accept: application/json" $Url 2>&1 + if ($LASTEXITCODE -ne 0) { + throw "curl GET erreur (exit code $LASTEXITCODE): $output" + } + return ($output | Out-String) +} + +function Invoke-CurlPost { + param( + [string]$Url, + [string]$Username, + [AllowEmptyString()][string]$Password, + [string]$BodyJson + ) + $output = & curl.exe -s -k -u "${Username}:${Password}" -H "Content-Type: application/json" -H "Accept: application/json" -X POST -d $BodyJson $Url 2>&1 + if ($LASTEXITCODE -ne 0) { + throw "curl POST erreur (exit code $LASTEXITCODE): $output" + } + return ($output | Out-String) +} + +# ===================================================================== +# 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" = "application/json" + } +} + +# ===================================================================== +# FONCTIONS : API v2 - interfaces reseau IPv6 +# ===================================================================== +function Get-NetworkInterfacesUrl { + param([string]$BaseUrl) + return "$BaseUrl/api/rest/v2/services/platform/network/interfaces" +} + +function Get-InterfaceIpv6Url { + param([string]$BaseUrl, [string]$InterfaceName) + return "$BaseUrl/api/rest/v2/services/platform/network/interfaces/$InterfaceName/ipv6" +} + +function Invoke-NetworkInterfacesGet { + param( + [string]$Url, + [string]$Username, + [AllowEmptyString()][string]$Password + ) + $headers = Get-AuthHeader -Username $Username -Password $Password + try { + $response = Invoke-WebRequest -Uri $Url -Method GET -Headers $headers -UseBasicParsing -TimeoutSec 30 + return $response.Content + } + catch { + if ((Test-SslError -Exception $_.Exception) -and $script:CurlAvailable) { + Write-Log -Message "Bascule sur curl.exe -k (echec TLS .NET)" -Level WARN + return Invoke-CurlGet -Url $Url -Username $Username -Password $Password + } + throw + } +} + +function Invoke-InterfaceIpv6Post { + param( + [string]$Url, + [string]$Username, + [AllowEmptyString()][string]$Password, + [bool]$Enabled + ) + $headers = Get-AuthHeader -Username $Username -Password $Password + $bodyJson = (@{ enabled = $Enabled } | ConvertTo-Json -Compress) + try { + Invoke-WebRequest -Uri $Url -Method POST -Headers $headers -ContentType "application/json" -Body $bodyJson -UseBasicParsing -TimeoutSec 30 | Out-Null + } + catch { + if ((Test-SslError -Exception $_.Exception) -and $script:CurlAvailable) { + Write-Log -Message "Bascule sur curl.exe -k (echec TLS .NET)" -Level WARN + Invoke-CurlPost -Url $Url -Username $Username -Password $Password -BodyJson $bodyJson | Out-Null + return + } + throw + } +} + +function Get-Ipv6CapableInterfaces { + param([PSCustomObject]$InterfacesObject) + + $result = @() + foreach ($prop in $InterfacesObject.PSObject.Properties) { + if ($prop.Value.PSObject.Properties.Name -contains "ipv6") { + $result += [PSCustomObject]@{ + Name = $prop.Name + OldState = $prop.Value.ipv6.enabled + } + } + } + return $result +} + +# ===================================================================== +# INITIALISATION +# ===================================================================== +Initialize-ApiClient +Write-Log -Message "=== IPv6ManagerCLI demarre - Action: $Action ===" -Level INFO + +$automates = Read-AutomateCsv -CsvPath $CsvInput +$desiredState = ($Action -eq "Enable") + +$statsAutomates = 0 +$statsInterfacesOk = 0 +$statsInterfacesError = 0 +$resultRows = @() + +# ===================================================================== +# TRAITEMENT DE CHAQUE AUTOMATE +# ===================================================================== +foreach ($automate in $automates) { + $hostname = $automate.Hostname + $ip = $automate."Current Ip" + $statsAutomates++ + + $baseUrl = Get-BaseUrl -Automate $automate + if (-not $baseUrl) { + Write-Log -Message "[$hostname] Aucun port HTTP/HTTPS valide - ignore" -Level WARN + $resultRows += [PSCustomObject]@{ + Hostname = $hostname; IP = $ip; Interface = "" + AncienEtat = ""; NouvelEtat = "" + Statut = "Erreur"; Message = "Aucun port HTTP/HTTPS valide" + } + continue + } + + $creds = Get-Credentials -Automate $automate -DefaultUsername $Username -DefaultPassword $Password + + try { + $interfacesUrl = Get-NetworkInterfacesUrl -BaseUrl $baseUrl + Write-Log -Message "[$hostname] GET $interfacesUrl (user: $($creds.Username))" -Level INFO + $content = Invoke-NetworkInterfacesGet -Url $interfacesUrl -Username $creds.Username -Password $creds.Password + $interfaces = $content | ConvertFrom-Json + + $capableInterfaces = Get-Ipv6CapableInterfaces -InterfacesObject $interfaces + Write-Log -Message "[$hostname] $($capableInterfaces.Count) interface(s) IPv6-capable(s) detectee(s)" -Level INFO + + foreach ($iface in $capableInterfaces) { + $ipv6Url = Get-InterfaceIpv6Url -BaseUrl $baseUrl -InterfaceName $iface.Name + try { + Write-Log -Message "[$hostname] POST $ipv6Url (enabled=$desiredState)" -Level INFO + Invoke-InterfaceIpv6Post -Url $ipv6Url -Username $creds.Username -Password $creds.Password -Enabled $desiredState + Write-Log -Message "[$hostname] Interface '$($iface.Name)' IPv6 -> $Action" -Level OK + $statsInterfacesOk++ + $resultRows += [PSCustomObject]@{ + Hostname = $hostname; IP = $ip; Interface = $iface.Name + AncienEtat = $iface.OldState; NouvelEtat = $desiredState + Statut = "Succes"; Message = "" + } + } + catch { + Write-Log -Message "[$hostname] ERREUR interface '$($iface.Name)' : $($_.Exception.Message)" -Level ERROR + $statsInterfacesError++ + $resultRows += [PSCustomObject]@{ + Hostname = $hostname; IP = $ip; Interface = $iface.Name + AncienEtat = $iface.OldState; NouvelEtat = $desiredState + Statut = "Erreur"; Message = $_.Exception.Message + } + } + } + } + catch { + Write-Log -Message "[$hostname] ERREUR : $($_.Exception.Message)" -Level ERROR + $resultRows += [PSCustomObject]@{ + Hostname = $hostname; IP = $ip; Interface = "" + AncienEtat = ""; NouvelEtat = "" + Statut = "Erreur"; Message = $_.Exception.Message + } + } +} + +# ===================================================================== +# ECRITURE DU CSV DE RESULTAT +# ===================================================================== +$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm" +$outputFile = Join-Path (Get-Location) "ipv6manager_$timestamp.csv" +if ($resultRows.Count -gt 0) { + $resultRows | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8 -Delimiter ";" + Write-Log -Message "CSV de resultat ecrit : $outputFile ($($resultRows.Count) ligne(s))" -Level OK +} +else { + Write-Log -Message "Aucune donnee a ecrire dans le CSV de resultat" -Level WARN +} + +# ===================================================================== +# RESUME FINAL +# ===================================================================== +Write-Log -Message "========== RESUME ==========" -Level INFO +Write-Log -Message "Automates traites : $statsAutomates" -Level INFO +Write-Log -Message "Interfaces modifiees avec succes : $statsInterfacesOk" -Level INFO +Write-Log -Message "Interfaces en erreur : $statsInterfacesError" -Level $(if ($statsInterfacesError -gt 0) { "WARN" } else { "INFO" }) +Write-Log -Message "============================" -Level INFO diff --git a/README.md b/README.md new file mode 100644 index 0000000..9f73023 --- /dev/null +++ b/README.md @@ -0,0 +1,421 @@ + +# IPv6ManagerCLI + +Outil en ligne de commande pour activer ou désactiver l'IPv6 sur les interfaces réseau des automates **Distech Controls Eclypse Facilities** (API v2 uniquement), via leur API REST. + +--- + +> **IMPORTANT : Ce projet est un développement personnel indépendant.** +> +> Ce projet a été développé par Charles-Arthur DAVID à titre personnel. +> Distech Controls n'est pas responsable de ce projet et ne le supporte pas. +> Aucune demande de support ne sera prise en charge par Distech Controls. +> Distech Controls ne fournit aucune garantie ni assistance technique pour ce projet. + +--- + +## Prérequis + +- **Windows 10 ou 11** (PowerShell 5.1 est inclus par défaut, rien à installer) +- Un accès réseau aux automates Eclypse Facilities +- Les identifiants de connexion aux automates (par défaut : `admin` / mot de passe vide) +- Automates compatibles **API v2** (Eclypse Facilities). + +## Ce que fait cet outil + +Pour chaque automate listé dans un CSV : + +1. Récupère la liste des interfaces réseau (`GET /api/rest/v2/services/platform/network/interfaces`). +2. Détecte les interfaces IPv6-capables : celles possédant une section `ipv6` dans leur configuration (ex : `secondary`, `auxiliary`, `wireless`, `bridge`, `primary`). +3. Applique l'état demandé (`Enable` ou `Disable`) sur **chacune** de ces interfaces (`POST /api/rest/v2/services/platform/network/interfaces/{name}/ipv6` avec `{"enabled": true|false}`), indépendamment de leur état actuel. + +En cas d'erreur sur un automate ou une interface (injoignable, échec du POST...), le script logue l'erreur, marque la ligne concernée en erreur, et continue avec l'interface/l'automate suivant. + +Un CSV récapitulatif est généré à la fin, avec l'ancien et le nouvel état de chaque interface traitée. + +--- + +## Utilisation avec cadMasterCLI + +Ce script peut être piloté depuis **[cadMasterCLI](https://git.cadjou.net/DistechControls/cadMasterCLI)**, qui évite d'avoir à utiliser PowerShell manuellement. + +Quand ce script est sélectionné dans cadMasterCLI : + +- Les paramètres sont détectés automatiquement et affichés sous forme de champs : + - `Action` : RadioButtons `Enable` / `Disable` (valeurs du `[ValidateSet]`, `Disable` sélectionné par défaut) + - `CsvInput` : bouton "Parcourir" + zone de collage d'IPs (conversion automatique en CSV) + - `Username`, `Password` : champs texte +- Il suffit de renseigner les champs puis de lancer l'exécution depuis l'interface — aucune commande PowerShell à taper, aucune politique d'exécution à modifier manuellement. + +Se référer à la section suivante pour le détail des paramètres, du format du CSV attendu et du dépannage. + +--- + +## Utilisation en autonome + +### Vérifier que PowerShell est disponible + +Ouvrir un terminal (touche `Windows` + `R`, taper `powershell`, puis `Entrée`) et taper : + +```powershell +$PSVersionTable.PSVersion +``` + +Le numéro `Major` doit être **5 ou plus**. + +### Installation + +Aucune installation requise. Télécharger ou cloner le dépôt : + +``` +IPv6ManagerCLI/ (ce dépôt) +├── IPv6ManagerCLI.ps1 <- Script principal +└── README.md +``` + +### Utilisation + +#### Ouvrir PowerShell dans le bon dossier + +1. Ouvrir l'explorateur de fichiers et naviguer dans le dossier du dépôt +2. Cliquer dans la barre d'adresse, taper `powershell`, puis appuyer sur `Entrée` + +Ou bien dans un terminal PowerShell : + +```powershell +cd "C:\chemin\vers\IPv6ManagerCLI" +``` + +#### Politique d'exécution + +Si c'est la première fois, PowerShell peut bloquer l'exécution des scripts. Autoriser pour la session en cours : + +```powershell +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +``` + +Cette commande est sans risque : elle n'autorise les scripts que pour la fenêtre PowerShell en cours. + +#### Désactiver l'IPv6 (action par défaut) + +```powershell +.\IPv6ManagerCLI.ps1 -CsvInput ".\automates.csv" +``` + +#### Activer l'IPv6 + +```powershell +.\IPv6ManagerCLI.ps1 -Action Enable -CsvInput ".\automates.csv" +``` + +Avec un mot de passe : + +```powershell +.\IPv6ManagerCLI.ps1 -Action Enable -CsvInput ".\automates.csv" -Password "MonMotDePasse" +``` + +**Résultat** : Un fichier `ipv6manager_yyyy-MM-dd_HH-mm.csv` est créé dans le dossier courant, avec le détail par interface (ancien état, nouvel état, statut). + +#### Aide intégrée + +```powershell +Get-Help .\IPv6ManagerCLI.ps1 -Detailed +``` + +### Format du CSV d'entrée + +Le fichier CSV utilise le **point-virgule** (`;`) comme séparateur. + +#### Colonnes obligatoires + +| Colonne | Description | +|---------|-------------| +| `Hostname` | Nom de l'automate | +| `Current Ip` | Adresse IP de l'automate | +| `HttpPort` | Port HTTP (`80` ou `-1` si désactivé) | +| `HttpsPort` | Port HTTPS (`443` ou `-1` si désactivé) | + +#### Colonnes optionnelles + +| Colonne | Description | +|---------|-------------| +| `Username` | Login spécifique à cet automate | +| `Password` | Mot de passe spécifique à cet automate | + +#### Exemple de CSV + +```csv +"Hostname";"Current Ip";"HttpPort";"HttpsPort" +"ECY-BATIMENT-01";"10.60.105.42";"-1";"443" +"ECY-BATIMENT-02";"10.60.105.44";"-1";"443" +``` + +### CSV de résultat + +Un fichier `ipv6manager_yyyy-MM-dd_HH-mm.csv` est généré dans le dossier courant, avec une ligne par interface traitée : + +| Colonne | Description | +|---------|-------------| +| `Hostname` | Nom de l'automate | +| `IP` | Adresse IP de l'automate | +| `Interface` | Nom de l'interface (secondary, auxiliary, wireless, bridge, primary...) | +| `AncienEtat` | État IPv6 avant modification (`True`/`False`) | +| `NouvelEtat` | État IPv6 appliqué (`True`/`False`) | +| `Statut` | `Succes` ou `Erreur` | +| `Message` | Détail de l'erreur si applicable | + +### Logs + +Chaque exécution affiche sa progression directement dans la console, avec un résumé final (automates traités, interfaces modifiées, interfaces en erreur). + +#### Niveaux de log + +| Niveau | Couleur console | Signification | +|--------|----------------|---------------| +| `INFO` | Cyan | Opération normale | +| `OK` | Vert | Opération réussie | +| `WARN` | Jaune | Avertissement (port invalide...) | +| `ERROR` | Rouge | Erreur (connexion échouée, automate injoignable...) | + +### Résumé des paramètres + +``` +.\IPv6ManagerCLI.ps1 [-Action ] -CsvInput [-Username ] [-Password ] +``` + +| Paramètre | Obligatoire | Défaut | Description | +|-----------|:-----------:|--------|-------------| +| `-Action` | Non | `Disable` | `Enable` ou `Disable` | +| `-CsvInput` | Oui | — | Chemin du fichier CSV d'entrée | +| `-Username` | Non | `admin` | Login API (surchargeable par le CSV) | +| `-Password` | Non | *(vide)* | Mot de passe API (surchargeable par le CSV) | + +### Dépannage + +#### "Impossible d'exécuter le script car l'exécution de scripts est désactivée" + +```powershell +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +``` + +#### "Aucun port HTTP/HTTPS valide" + +Vérifier que les colonnes `HttpPort` et `HttpsPort` du CSV contiennent des valeurs valides. Un port à `-1` signifie "désactivé". Au moins un des deux doit être actif. + +#### Timeout ou erreur de connexion + +- Vérifier que l'automate est joignable (`ping 10.60.105.x`) +- Vérifier les identifiants (Username / Password) +- Vérifier que le port est correct (HTTP 80 ou HTTPS 443) +- Vérifier que l'automate est bien un Eclypse Facilities compatible API v2 + + +# IPv6ManagerCLI + +Command-line tool to enable or disable IPv6 on the network interfaces of **Distech Controls Eclypse Facilities** controllers (API v2 only), via their REST API. + +--- + +> **IMPORTANT: This project is an independent personal development.** +> +> This project was developed by Charles-Arthur DAVID on a personal basis. +> Distech Controls is not responsible for this project and does not support it. +> No support requests will be handled by Distech Controls. +> Distech Controls provides no warranty or technical assistance for this project. + +--- + +## Prerequisites + +- **Windows 10 or 11** (PowerShell 5.1 is included by default, nothing to install) +- Network access to the Eclypse Facilities controllers +- Login credentials for the controllers (default: `admin` / empty password) +- Controllers compatible with **API v2** (Eclypse Facilities). + +## What this tool does + +For each controller listed in a CSV: + +1. Retrieves the list of network interfaces (`GET /api/rest/v2/services/platform/network/interfaces`). +2. Detects IPv6-capable interfaces: those with an `ipv6` section in their configuration (e.g. `secondary`, `auxiliary`, `wireless`, `bridge`, `primary`). +3. Applies the requested state (`Enable` or `Disable`) on **each** of these interfaces (`POST /api/rest/v2/services/platform/network/interfaces/{name}/ipv6` with `{"enabled": true|false}`), regardless of their current state. + +On error for a controller or interface (unreachable, failed POST...), the script logs the error, flags the row as an error, and continues with the next interface/controller. + +A summary CSV is generated at the end, with the old and new state of each processed interface. + +--- + +## Using with cadMasterCLI + +This script can be run from **[cadMasterCLI](https://git.cadjou.net/DistechControls/cadMasterCLI)**, which avoids having to use PowerShell manually. + +When this script is selected in cadMasterCLI: + +- Parameters are detected automatically and rendered as input fields: + - `Action`: RadioButtons `Enable` / `Disable` (values from `[ValidateSet]`, `Disable` selected by default) + - `CsvInput`: a "Browse" button plus an IP paste area (automatic conversion to CSV) + - `Username`, `Password`: text fields +- Simply fill in the fields and launch the run from the interface — no PowerShell command to type, no execution policy to change manually. + +See the next section for parameter details, the expected CSV format, and troubleshooting. + +--- + +## Standalone usage + +### Check that PowerShell is available + +Open a terminal (`Windows` key + `R`, type `powershell`, then `Enter`) and type: + +```powershell +$PSVersionTable.PSVersion +``` + +The `Major` number must be **5 or higher**. + +### Installation + +No installation required. Download or clone this repository: + +``` +IPv6ManagerCLI/ (this repo) +├── IPv6ManagerCLI.ps1 <- Main script +└── README.md +``` + +### Usage + +#### Open PowerShell in the right folder + +1. Open File Explorer and navigate to the repository folder +2. Click in the address bar, type `powershell`, then press `Enter` + +Or in a PowerShell terminal: + +```powershell +cd "C:\path\to\IPv6ManagerCLI" +``` + +#### Execution policy + +The first time, PowerShell may block script execution. Allow it for the current session: + +```powershell +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +``` + +This command is safe: it only allows scripts for the current PowerShell window. + +#### Disable IPv6 (default action) + +```powershell +.\IPv6ManagerCLI.ps1 -CsvInput ".\controllers.csv" +``` + +#### Enable IPv6 + +```powershell +.\IPv6ManagerCLI.ps1 -Action Enable -CsvInput ".\controllers.csv" +``` + +With a password: + +```powershell +.\IPv6ManagerCLI.ps1 -Action Enable -CsvInput ".\controllers.csv" -Password "MyPassword" +``` + +**Result**: A file `ipv6manager_yyyy-MM-dd_HH-mm.csv` is created in the current folder, with per-interface detail (old state, new state, status). + +#### Built-in help + +```powershell +Get-Help .\IPv6ManagerCLI.ps1 -Detailed +``` + +### Input CSV format + +The CSV file uses a **semicolon** (`;`) as separator. + +#### Required columns + +| Column | Description | +|---------|-------------| +| `Hostname` | Controller name | +| `Current Ip` | Controller IP address | +| `HttpPort` | HTTP port (`80` or `-1` if disabled) | +| `HttpsPort` | HTTPS port (`443` or `-1` if disabled) | + +#### Optional columns + +| Column | Description | +|---------|-------------| +| `Username` | Login specific to this controller | +| `Password` | Password specific to this controller | + +#### CSV example + +```csv +"Hostname";"Current Ip";"HttpPort";"HttpsPort" +"ECY-BUILDING-01";"10.60.105.42";"-1";"443" +"ECY-BUILDING-02";"10.60.105.44";"-1";"443" +``` + +### Result CSV + +A file `ipv6manager_yyyy-MM-dd_HH-mm.csv` is generated in the current folder, with one row per processed interface: + +| Column | Description | +|---------|-------------| +| `Hostname` | Controller name | +| `IP` | Controller IP address | +| `Interface` | Interface name (secondary, auxiliary, wireless, bridge, primary...) | +| `AncienEtat` | IPv6 state before the change (`True`/`False`) | +| `NouvelEtat` | Applied IPv6 state (`True`/`False`) | +| `Statut` | `Succes` or `Erreur` | +| `Message` | Error detail if applicable | + +### Logs + +Each run displays its progress directly in the console, with a final summary (controllers processed, interfaces changed, interfaces in error). + +#### Log levels + +| Level | Console color | Meaning | +|--------|----------------|---------------| +| `INFO` | Cyan | Normal operation | +| `OK` | Green | Successful operation | +| `WARN` | Yellow | Warning (invalid port...) | +| `ERROR` | Red | Error (connection failed, controller unreachable...) | + +### Parameters summary + +``` +.\IPv6ManagerCLI.ps1 [-Action ] -CsvInput [-Username ] [-Password ] +``` + +| Parameter | Required | Default | Description | +|-----------|:-----------:|--------|-------------| +| `-Action` | No | `Disable` | `Enable` or `Disable` | +| `-CsvInput` | Yes | — | Path to the input CSV file | +| `-Username` | No | `admin` | API login (overridable by the CSV) | +| `-Password` | No | *(empty)* | API password (overridable by the CSV) | + +### Troubleshooting + +#### "Cannot run the script because script execution is disabled" + +```powershell +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +``` + +#### "No valid HTTP/HTTPS port" + +Check that the CSV's `HttpPort` and `HttpsPort` columns contain valid values. A port set to `-1` means "disabled". At least one of the two must be active. + +#### Timeout or connection error + +- Check that the controller is reachable (`ping 10.60.105.x`) +- Check the credentials (Username / Password) +- Check that the port is correct (HTTP 80 or HTTPS 443) +- Check that the controller is an Eclypse Facilities unit compatible with API v2