diff --git a/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs b/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
index 62305e6..ff4a63b 100644
--- a/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
+++ b/ZA.CoreService.ESBCertificateManager/Models/SonicConnection.cs
@@ -21,9 +21,27 @@ public sealed class SonicConnection
///
public required string ConnectionUrl { get; init; }
+ /// Sonic SMC / Domain Manager Login (nicht für WinRM).
public required string Username { get; init; }
+
+ /// Sonic SMC / Domain Manager Passwort (nicht für WinRM).
public required string Password { get; init; }
+ ///
+ /// Windows-Konto für WinRM (Invoke-Command -Credential).
+ /// Leer = aktueller Prozess-Benutzer ohne explizite Credentials.
+ /// Nicht mit / (Sonic SMC) verwechseln.
+ ///
+ public string WinRmUsername { get; init; } = string.Empty;
+
+ /// Windows-Passwort für WinRM; nur relevant wenn gesetzt ist.
+ public string WinRmPassword { get; init; } = string.Empty;
+
+ ///
+ /// WinRm = remote via PowerShell Remoting;
+ /// LocalCmd = lokal auf dem Sonic-Server (kein WinRM, App muss dort laufen);
+ /// HttpApi = REST.
+ ///
public SonicManagementMode ManagementMode { get; init; } = SonicManagementMode.WinRm;
/// Sonic-Installationsroot, z.B. "C:\Sonic\MQ10.0".
diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
index 11f633b..eca3359 100644
--- a/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
+++ b/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
@@ -11,9 +11,11 @@ namespace ZA.CoreService.ESBCertificateManager.Services;
///
/// Modus = WinRm (Standard):
/// PowerShell Remoting (Invoke-Command) → CMD stop/startcontainer auf dem Sonic-Server.
+/// WinRM nutzt WinRmUsername/WinRmPassword (Windows); leer = aktueller Benutzer.
+/// Username/Password bleiben Sonic-SMC-/Domain-Manager-Logins.
///
/// Modus = LocalCmd:
-/// Dieselbe CMD/PowerShell-Logik lokal (Test direkt auf dem Sonic-PC).
+/// Dieselbe CMD/PowerShell-Logik lokal (App muss auf dem Sonic-PC laufen; kein WinRM).
///
/// Modus = HttpApi:
/// HTTP REST API mit automatischer Pfad-Erkennung.
diff --git a/ZA.CoreService.ESBCertificateManager/Services/WinRmExecutor.cs b/ZA.CoreService.ESBCertificateManager/Services/WinRmExecutor.cs
index 7cbd386..858775c 100644
--- a/ZA.CoreService.ESBCertificateManager/Services/WinRmExecutor.cs
+++ b/ZA.CoreService.ESBCertificateManager/Services/WinRmExecutor.cs
@@ -21,6 +21,9 @@ public sealed class WinRmExecutor
_connection = connection;
}
+ private bool HasExplicitWinRmCredentials
+ => !string.IsNullOrWhiteSpace(_connection.WinRmUsername);
+
public async Task<(bool Success, string? Error)> TestConnectionAsync(
CancellationToken cancellationToken = default)
{
@@ -56,7 +59,7 @@ public sealed class WinRmExecutor
return sessionOk
? (true, null)
- : (false, $"WinRM-Verbindung fehlgeschlagen: {sessionError}");
+ : (false, sessionError ?? "WinRM-Verbindung fehlgeschlagen.");
}
public async Task<(bool Success, string? Output, string? Error)> RunScriptAsync(
@@ -119,8 +122,15 @@ public sealed class WinRmExecutor
return (true, stdout, stderr.Length > 0 ? stderr : null);
}
- return (false, stdout.Length > 0 ? stdout : null,
- stderr.Length > 0 ? Truncate(stderr) : $"PowerShell ExitCode={process.ExitCode}");
+ string rawError = stderr.Length > 0
+ ? stderr
+ : $"PowerShell ExitCode={process.ExitCode}";
+
+ string error = _connection.ManagementMode == SonicManagementMode.WinRm
+ ? FormatWinRmFailure(rawError)
+ : Truncate(rawError);
+
+ return (false, stdout.Length > 0 ? stdout : null, error);
}
finally
{
@@ -134,24 +144,99 @@ public sealed class WinRmExecutor
///
/// Remote-Payload als Base64 einbetten und per [scriptblock]::Create ausführen.
/// Vermeidet verschachteltes ScriptBlock-Brace-Nesting und lokale $-Expansion.
+ /// WinRM-Credentials: nur / WinRmPassword.
+ /// Leer = aktueller Windows-Benutzer (ohne -Credential).
///
private string BuildRemoteScript(string host, string scriptBlock)
{
- string escapedPwd = _connection.Password.Replace("'", "''");
- string escapedUser = _connection.Username.Replace("'", "''");
string escapedHost = host.Replace("'", "''");
string remoteB64 = Convert.ToBase64String(Encoding.Unicode.GetBytes(scriptBlock));
+ StringBuilder sb = new();
+ sb.Append("$ErrorActionPreference = 'Stop'\n");
+
+ if (HasExplicitWinRmCredentials)
+ {
+ string escapedPwd = (_connection.WinRmPassword ?? string.Empty).Replace("'", "''");
+ string escapedUser = _connection.WinRmUsername.Replace("'", "''");
+ sb.Append($"$secPwd = ConvertTo-SecureString '{escapedPwd}' -AsPlainText -Force\n");
+ sb.Append($"$cred = New-Object System.Management.Automation.PSCredential('{escapedUser}', $secPwd)\n");
+ }
+
+ sb.Append($"$remoteB64 = '{remoteB64}'\n");
+ sb.Append("$remoteScript = [System.Text.Encoding]::Unicode.GetString(");
+ sb.Append("[System.Convert]::FromBase64String($remoteB64))\n");
+ sb.Append("$sb = [scriptblock]::Create($remoteScript)\n");
+ sb.Append($"Invoke-Command -ComputerName '{escapedHost}' -Port {_connection.WinRmPort} ");
+
+ if (HasExplicitWinRmCredentials)
+ {
+ sb.Append("-Credential $cred ");
+ }
+
+ sb.Append("-ScriptBlock $sb -ErrorAction Stop");
+ return sb.ToString();
+ }
+
+ ///
+ /// Erkennt typische WinRM-/Windows-Auth-Fehler und liefert eine klare Handlungsanweisung.
+ /// Username/Password in appsettings sind Sonic-SMC – nicht Windows/WinRM.
+ ///
+ private string FormatWinRmFailure(string rawError)
+ {
+ string truncated = Truncate(rawError);
+ if (!LooksLikeWinRmAuthFailure(rawError))
+ {
+ return truncated;
+ }
+
+ string authHint = HasExplicitWinRmCredentials
+ ? "WinRmUsername/WinRmPassword prüfen (Windows-Konto mit WinRM-Rechten auf dem Zielrechner)."
+ : "Aktueller Windows-Benutzer hat keine WinRM-Berechtigung auf dem Zielrechner " +
+ "(oder Kerberos/CredSSP fehlt). WinRmUsername/WinRmPassword setzen " +
+ "oder App unter einem berechtigten Windows-Konto starten.";
+
return
- "$ErrorActionPreference = 'Stop'\n" +
- $"$secPwd = ConvertTo-SecureString '{escapedPwd}' -AsPlainText -Force\n" +
- $"$cred = New-Object System.Management.Automation.PSCredential('{escapedUser}', $secPwd)\n" +
- $"$remoteB64 = '{remoteB64}'\n" +
- "$remoteScript = [System.Text.Encoding]::Unicode.GetString(" +
- "[System.Convert]::FromBase64String($remoteB64))\n" +
- "$sb = [scriptblock]::Create($remoteScript)\n" +
- $"Invoke-Command -ComputerName '{escapedHost}' -Port {_connection.WinRmPort} " +
- "-Credential $cred -ScriptBlock $sb -ErrorAction Stop";
+ "WinRM-Authentifizierung fehlgeschlagen: Windows-Anmeldedaten falsch oder fehlend.\n" +
+ "Hinweis: Username/Password in appsettings sind Sonic-SMC-/Domain-Manager-Logins – " +
+ "NICHT für WinRM/Windows.\n" +
+ authHint + "\n" +
+ "Alternativen:\n" +
+ " • ManagementMode=LocalCmd setzen und die App direkt auf dem Sonic-Server starten (kein WinRM).\n" +
+ " • WinRmUsername/WinRmPassword mit gültigem Windows-Konto befüllen.\n" +
+ $"Details: {truncated}";
+ }
+
+ private static bool LooksLikeWinRmAuthFailure(string error)
+ {
+ if (string.IsNullOrEmpty(error))
+ {
+ return false;
+ }
+
+ ReadOnlySpan markers =
+ [
+ "Benutzername oder das Kennwort ist falsch",
+ "username or password is incorrect",
+ "Access is denied",
+ "Zugriff verweigert",
+ "Logon failure",
+ "Anmeldefehler",
+ "PSRemotingTransportException",
+ "UnauthorizedAccess",
+ "WinRM cannot process the request",
+ "der remotecomputer hat den netzwerkdatenverkehr verweigert"
+ ];
+
+ foreach (string marker in markers)
+ {
+ if (error.Contains(marker, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ return false;
}
public static string ApplyScriptTemplate(
diff --git a/ZA.CoreService.ESBCertificateManager/appsettings.json b/ZA.CoreService.ESBCertificateManager/appsettings.json
index 5d7e440..528b2cb 100644
--- a/ZA.CoreService.ESBCertificateManager/appsettings.json
+++ b/ZA.CoreService.ESBCertificateManager/appsettings.json
@@ -10,8 +10,13 @@
"Name": "DE-Test",
"DomainName": "proalpha-test",
"ConnectionUrl": "tcp://dekun-painwbdet:13070",
+ // Sonic SMC / Domain Manager (NICHT für WinRM):
"Username": "Administrator",
"Password": "Administrator",
+ // Windows für WinRM: leer = aktueller Benutzer (z.B. gisler). Nie Sonic-SMC-Logins hier eintragen.
+ // Lokal auf dem Sonic-Server testen: ManagementMode auf "LocalCmd" setzen (kein WinRM nötig).
+ "WinRmUsername": "",
+ "WinRmPassword": "",
"ManagementMode": "WinRm",
"SonicHome": "C:\\Sonic\\MQ10.0",
"KnownContainers": [