Diagnose BizTalk WMI SQL permissions
This commit is contained in:
@@ -96,6 +96,7 @@ namespace BizTalkCheckmkPulse
|
||||
detail.Append(available ? "BizTalk WMI and platform data reachable" : "BizTalk WMI or required platform data not readable");
|
||||
detail.Append(", server=").Append(EmptyAsUnknown(result.Platform.ServerName));
|
||||
AppendOptional(detail, "group", result.Platform.GroupName);
|
||||
AppendOptional(detail, "operator_group", result.Platform.OperatorGroup);
|
||||
AppendOptional(detail, "mgmt_db", JoinDb(result.Platform.ManagementDbServer, result.Platform.ManagementDbName));
|
||||
AppendOptional(detail, "msgbox_db", JoinDb(result.Platform.MessageBoxDbServer, result.Platform.MessageBoxDbName));
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ namespace BizTalkCheckmkPulse
|
||||
public bool RuntimeArtifactsDataAvailable { get; set; }
|
||||
public string ServerName { get; set; }
|
||||
public string GroupName { get; set; }
|
||||
public string OperatorGroup { get; set; }
|
||||
public string ManagementDbServer { get; set; }
|
||||
public string ManagementDbName { get; set; }
|
||||
public string MessageBoxDbServer { get; set; }
|
||||
|
||||
@@ -39,14 +39,25 @@ namespace BizTalkCheckmkPulse
|
||||
|
||||
if (!result.Platform.PlatformDataAvailable)
|
||||
{
|
||||
var wmiPermissionFailure = result.Diagnostics.Any(x =>
|
||||
x.Area == DiagnosticArea.Wmi
|
||||
&& x.Category == DiagnosticCategory.Permission
|
||||
&& x.Required
|
||||
&& string.Equals(x.Component, "MSBTS_GroupSetting", StringComparison.OrdinalIgnoreCase));
|
||||
result.Diagnostics.Add(new ProbeDiagnostic
|
||||
{
|
||||
Area = DiagnosticArea.Sql,
|
||||
Category = DiagnosticCategory.Configuration,
|
||||
Category = wmiPermissionFailure
|
||||
? DiagnosticCategory.Permission
|
||||
: DiagnosticCategory.Configuration,
|
||||
Component = "BizTalk database discovery",
|
||||
Required = true,
|
||||
Summary = "SQL-Zielermittlung ist unvollstaendig, weil nicht alle erforderlichen BizTalk-Plattformklassen gelesen wurden.",
|
||||
Action = "Zuerst den Service 'BizTalk Platform' und MSBTS_GroupSetting pruefen. Danach den Agent-Dump erneut ausfuehren."
|
||||
Summary = wmiPermissionFailure
|
||||
? "SQL-Zielermittlung ist unvollstaendig, weil der BizTalk-WMI-Provider beim SQL-Zugriff abgewiesen wurde."
|
||||
: "SQL-Zielermittlung ist unvollstaendig, weil nicht alle erforderlichen BizTalk-Plattformklassen gelesen wurden.",
|
||||
Action = wmiPermissionFailure
|
||||
? "Zuerst die Wmi/Permission-Diagnose und die Mitgliedschaft des Computerkontos in der konfigurierten BizTalk-Operator-Gruppe beheben."
|
||||
: "Zuerst den Service 'BizTalk Platform' und MSBTS_GroupSetting pruefen. Danach den Agent-Dump erneut ausfuehren."
|
||||
});
|
||||
}
|
||||
|
||||
@@ -75,9 +86,19 @@ namespace BizTalkCheckmkPulse
|
||||
var isLocalSystem = identity != null
|
||||
&& identity.User != null
|
||||
&& identity.User.IsWellKnown(WellKnownSidType.LocalSystemSid);
|
||||
result.NetworkIdentityHint = isLocalSystem
|
||||
? "<DOMAIN>\\" + Environment.MachineName + "$"
|
||||
: result.ExecutionIdentity;
|
||||
if (isLocalSystem)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(result.NetworkIdentityHint)
|
||||
|| string.Equals(result.NetworkIdentityHint, "unknown", StringComparison.OrdinalIgnoreCase)
|
||||
|| result.NetworkIdentityHint.StartsWith("<DOMAIN>\\", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.NetworkIdentityHint = "<DOMAIN>\\" + Environment.MachineName + "$";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.NetworkIdentityHint = result.ExecutionIdentity;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace BizTalkCheckmkPulse
|
||||
private const int OrchestrationStarted = 4;
|
||||
private const int EAccessDenied = unchecked((int)0x80070005);
|
||||
internal const string GroupSettingQuery =
|
||||
"SELECT Name, MgmtDbServerName, MgmtDbName, SubscriptionDBServerName, SubscriptionDBName FROM MSBTS_GroupSetting";
|
||||
"SELECT Name, BizTalkOperatorGroup, MgmtDbServerName, MgmtDbName, SubscriptionDBServerName, SubscriptionDBName FROM MSBTS_GroupSetting";
|
||||
private readonly MonitoringOptions _options;
|
||||
|
||||
/// <summary>
|
||||
@@ -105,6 +105,7 @@ namespace BizTalkCheckmkPulse
|
||||
|
||||
groupFound = true;
|
||||
result.Platform.GroupName = FirstNonEmpty(WmiHelpers.GetString(item, "Name"), WmiHelpers.GetString(item, "MgmtDbName"));
|
||||
result.Platform.OperatorGroup = WmiHelpers.GetString(item, "BizTalkOperatorGroup");
|
||||
result.Platform.ManagementDbServer = WmiHelpers.GetString(item, "MgmtDbServerName");
|
||||
result.Platform.ManagementDbName = WmiHelpers.GetString(item, "MgmtDbName");
|
||||
result.Platform.MessageBoxDbServer = WmiHelpers.GetString(item, "SubscriptionDBServerName");
|
||||
@@ -502,6 +503,12 @@ namespace BizTalkCheckmkPulse
|
||||
TimeSpan? duration)
|
||||
{
|
||||
var category = ClassifyWmiException(exception);
|
||||
var sqlLoginPrincipal = ExtractSqlLoginPrincipal(exception.Message);
|
||||
if (!string.IsNullOrWhiteSpace(sqlLoginPrincipal))
|
||||
{
|
||||
result.NetworkIdentityHint = sqlLoginPrincipal;
|
||||
}
|
||||
|
||||
var technicalDetails = exception.GetType().Name
|
||||
+ " HRESULT=0x" + exception.HResult.ToString("X8")
|
||||
+ ": " + exception.Message;
|
||||
@@ -521,8 +528,8 @@ namespace BizTalkCheckmkPulse
|
||||
Category = category,
|
||||
Component = component,
|
||||
Required = required,
|
||||
Summary = BuildWmiSummary(category, component, connectionFailure),
|
||||
Action = BuildWmiAction(category, connectionFailure),
|
||||
Summary = BuildWmiSummary(category, component, connectionFailure, sqlLoginPrincipal),
|
||||
Action = BuildWmiAction(category, connectionFailure, sqlLoginPrincipal),
|
||||
TechnicalDetails = technicalDetails
|
||||
});
|
||||
}
|
||||
@@ -551,7 +558,7 @@ namespace BizTalkCheckmkPulse
|
||||
/// </summary>
|
||||
/// <param name="exception">Zu klassifizierende Exception.</param>
|
||||
/// <returns>Handlungsorientierte Diagnosekategorie.</returns>
|
||||
private static DiagnosticCategory ClassifyWmiException(Exception exception)
|
||||
internal static DiagnosticCategory ClassifyWmiException(Exception exception)
|
||||
{
|
||||
var managementException = exception as ManagementException;
|
||||
var comException = exception as COMException;
|
||||
@@ -583,6 +590,15 @@ namespace BizTalkCheckmkPulse
|
||||
}
|
||||
|
||||
var message = exception.Message ?? string.Empty;
|
||||
if (ContainsAny(
|
||||
message,
|
||||
"Login failed for user",
|
||||
"Cannot open database",
|
||||
"not associated with a trusted SQL Server connection"))
|
||||
{
|
||||
return DiagnosticCategory.Permission;
|
||||
}
|
||||
|
||||
if (ContainsAny(message, "timed out", "timeout", "Zeitlimit"))
|
||||
{
|
||||
return DiagnosticCategory.Timeout;
|
||||
@@ -596,6 +612,45 @@ namespace BizTalkCheckmkPulse
|
||||
return DiagnosticCategory.Provider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extrahiert das von SQL Server abgewiesene Konto aus der Provider-Fehlermeldung.
|
||||
/// </summary>
|
||||
/// <param name="message">WMI-/OLEDB-Fehlermeldung.</param>
|
||||
/// <returns>Abgewiesenes Konto oder eine leere Zeichenfolge.</returns>
|
||||
internal static string ExtractSqlLoginPrincipal(string message)
|
||||
{
|
||||
const string marker = "Login failed for user";
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var markerIndex = message.IndexOf(marker, StringComparison.OrdinalIgnoreCase);
|
||||
if (markerIndex < 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var valueStart = markerIndex + marker.Length;
|
||||
while (valueStart < message.Length
|
||||
&& (char.IsWhiteSpace(message[valueStart]) || message[valueStart] == ':'))
|
||||
{
|
||||
valueStart++;
|
||||
}
|
||||
|
||||
if (valueStart >= message.Length
|
||||
|| (message[valueStart] != '\'' && message[valueStart] != '"'))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var quote = message[valueStart];
|
||||
var valueEnd = message.IndexOf(quote, valueStart + 1);
|
||||
return valueEnd > valueStart + 1
|
||||
? message.Substring(valueStart + 1, valueEnd - valueStart - 1).Trim()
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Erstellt eine kurze Fehlerursache fuer einen WMI-Fehler.
|
||||
/// </summary>
|
||||
@@ -603,11 +658,20 @@ namespace BizTalkCheckmkPulse
|
||||
/// <param name="component">Betroffene Komponente.</param>
|
||||
/// <param name="connectionFailure">Kennzeichen fuer den Namespace-Verbindungsaufbau.</param>
|
||||
/// <returns>Menschenlesbare Fehlerzusammenfassung.</returns>
|
||||
private static string BuildWmiSummary(DiagnosticCategory category, string component, bool connectionFailure)
|
||||
private static string BuildWmiSummary(
|
||||
DiagnosticCategory category,
|
||||
string component,
|
||||
bool connectionFailure,
|
||||
string sqlLoginPrincipal)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case DiagnosticCategory.Permission:
|
||||
if (!string.IsNullOrWhiteSpace(sqlLoginPrincipal))
|
||||
{
|
||||
return "BizTalk-WMI-Provider konnte den SQL-Zugriff fuer " + sqlLoginPrincipal + " nicht anmelden.";
|
||||
}
|
||||
|
||||
return "Zugriff auf " + component + " wurde im LocalSystem-Kontext verweigert.";
|
||||
case DiagnosticCategory.Configuration:
|
||||
return connectionFailure
|
||||
@@ -630,11 +694,20 @@ namespace BizTalkCheckmkPulse
|
||||
/// <param name="category">Klassifizierte Fehlerart.</param>
|
||||
/// <param name="connectionFailure">Kennzeichen fuer den Namespace-Verbindungsaufbau.</param>
|
||||
/// <returns>Empfohlener Diagnoseschritt.</returns>
|
||||
private static string BuildWmiAction(DiagnosticCategory category, bool connectionFailure)
|
||||
private static string BuildWmiAction(
|
||||
DiagnosticCategory category,
|
||||
bool connectionFailure,
|
||||
string sqlLoginPrincipal)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case DiagnosticCategory.Permission:
|
||||
if (!string.IsNullOrWhiteSpace(sqlLoginPrincipal))
|
||||
{
|
||||
return "Computerkonto " + sqlLoginPrincipal
|
||||
+ " der in der BizTalk-Gruppe konfigurierten BizTalk-Operator-Gruppe zuordnen; keine direkten SQL-Logins oder Datenbankrollen vergeben.";
|
||||
}
|
||||
|
||||
return connectionFailure
|
||||
? "Namespace-ACL fuer root\\MicrosoftBizTalkServer gezielt pruefen. LocalSystem benoetigt lokalen Lesezugriff; keine pauschalen WMI-Rechte vergeben."
|
||||
: "Agent-Dump pruefen und Computerkonto <DOMAIN>\\" + Environment.MachineName + "$ zunaechst der konfigurierten BizTalk-Operator-Gruppe zuordnen.";
|
||||
|
||||
Reference in New Issue
Block a user