Stabilize BizTalk inventory collection and diagnostics
Build und Test / build (push) Has been cancelled
Build und Test / build (push) Has been cancelled
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Management;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Microsoft.Win32;
|
||||
using BizTalkSapEnvironmentInventory.Configuration;
|
||||
using BizTalkSapEnvironmentInventory.Infrastructure;
|
||||
using BizTalkSapEnvironmentInventory.Models;
|
||||
|
||||
namespace BizTalkSapEnvironmentInventory.Collectors
|
||||
@@ -17,10 +22,17 @@ namespace BizTalkSapEnvironmentInventory.Collectors
|
||||
private const string AdministrationKey = BizTalkKey + @"\Administration";
|
||||
|
||||
private readonly CommandLineOptions options;
|
||||
private readonly ConsoleFileLogger logger;
|
||||
private readonly TimeSpan timeout;
|
||||
|
||||
public SystemCollector(CommandLineOptions options)
|
||||
public SystemCollector(
|
||||
CommandLineOptions options,
|
||||
ConsoleFileLogger logger,
|
||||
int timeoutSeconds)
|
||||
{
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
timeout = TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,8 +55,11 @@ namespace BizTalkSapEnvironmentInventory.Collectors
|
||||
".NET Runtime",
|
||||
Environment.Version.ToString()));
|
||||
|
||||
logger.Info("Lese lokale Windows-Betriebssysteminformationen.");
|
||||
CollectOperatingSystem(document);
|
||||
logger.Info("Lese lokale BizTalk-Installation aus der Registry.");
|
||||
CollectBizTalkRegistry(document);
|
||||
logger.Info("Ermittle die BizTalk-Gruppe über MSBTS_GroupSetting.");
|
||||
CollectBizTalkGroupSetting(document);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(options.ManagementServer))
|
||||
@@ -67,6 +82,11 @@ namespace BizTalkSapEnvironmentInventory.Collectors
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"BizTalk Management Database",
|
||||
EmptyAsUnknown(document.System.ManagementDatabase)));
|
||||
logger.Info("Management-Datenbankziel: Server="
|
||||
+ EmptyAsUnknown(document.System.ManagementServer)
|
||||
+ "; Datenbank="
|
||||
+ EmptyAsUnknown(document.System.ManagementDatabase)
|
||||
+ ".");
|
||||
|
||||
if (!string.Equals(document.EnvironmentName, "ACC", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(document.EnvironmentName, "PROD", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -82,78 +102,146 @@ namespace BizTalkSapEnvironmentInventory.Collectors
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectOperatingSystem(InventoryDocument document)
|
||||
private void CollectOperatingSystem(InventoryDocument document)
|
||||
{
|
||||
using (var searcher = new ManagementObjectSearcher(
|
||||
"root\\cimv2",
|
||||
"SELECT Caption,Version,BuildNumber,OSArchitecture,LastBootUpTime FROM Win32_OperatingSystem"))
|
||||
const string query =
|
||||
"SELECT Caption,Version,BuildNumber,OSArchitecture,LastBootUpTime "
|
||||
+ "FROM Win32_OperatingSystem";
|
||||
var timer = Stopwatch.StartNew();
|
||||
logger.Detail("WMI-Namespace: root\\cimv2");
|
||||
logger.Detail("WQL: " + query);
|
||||
try
|
||||
{
|
||||
foreach (ManagementObject item in searcher.Get())
|
||||
using (var searcher = new ManagementObjectSearcher("root\\cimv2", query))
|
||||
{
|
||||
document.System.Properties.Add(new NameValueRecord("Betriebssystem", Value(item, "Caption")));
|
||||
document.System.Properties.Add(new NameValueRecord("Windows-Version", Value(item, "Version")));
|
||||
document.System.Properties.Add(new NameValueRecord("Windows-Build", Value(item, "BuildNumber")));
|
||||
document.System.Properties.Add(new NameValueRecord("Architektur", Value(item, "OSArchitecture")));
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"Letzter Systemstart",
|
||||
ConvertWmiDate(Value(item, "LastBootUpTime"))));
|
||||
break;
|
||||
ConfigureSearcher(searcher);
|
||||
using (var rows = searcher.Get())
|
||||
{
|
||||
var count = 0;
|
||||
foreach (ManagementObject item in rows)
|
||||
{
|
||||
using (item)
|
||||
{
|
||||
count++;
|
||||
if (count != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"Betriebssystem",
|
||||
Value(item, "Caption")));
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"Windows-Version",
|
||||
Value(item, "Version")));
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"Windows-Build",
|
||||
Value(item, "BuildNumber")));
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"Architektur",
|
||||
Value(item, "OSArchitecture")));
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"Letzter Systemstart",
|
||||
ConvertWmiDate(Value(item, "LastBootUpTime"))));
|
||||
}
|
||||
}
|
||||
timer.Stop();
|
||||
logger.Info("Windows-WMI-Abfrage abgeschlossen: Datensätze="
|
||||
+ count + "; Dauer=" + timer.ElapsedMilliseconds + " ms.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception) when (IsRecoverableWmiException(exception))
|
||||
{
|
||||
timer.Stop();
|
||||
document.Findings.Add(new Finding
|
||||
{
|
||||
Severity = "Warnung",
|
||||
Area = "Windows WMI",
|
||||
Message = "Win32_OperatingSystem konnte nicht gelesen werden: "
|
||||
+ exception.Message,
|
||||
RecommendedAction =
|
||||
"Lokalen WMI-Dienst und Leseberechtigungen prüfen; "
|
||||
+ "die BizTalk-Erfassung wird fortgesetzt.",
|
||||
Owner = "Windows-/BizTalk-Betrieb"
|
||||
});
|
||||
logger.Exception("Windows-WMI-Abfrage fehlgeschlagen", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectBizTalkRegistry(InventoryDocument document)
|
||||
private void CollectBizTalkRegistry(InventoryDocument document)
|
||||
{
|
||||
foreach (var view in new[] { RegistryView.Registry64, RegistryView.Registry32 })
|
||||
{
|
||||
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view))
|
||||
using (var product = baseKey.OpenSubKey(BizTalkKey, false))
|
||||
logger.Detail("Prüfe BizTalk-Registryansicht: " + view + ".");
|
||||
try
|
||||
{
|
||||
if (product != null)
|
||||
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view))
|
||||
using (var product = baseKey.OpenSubKey(BizTalkKey, false))
|
||||
{
|
||||
AddRegistryValue(document, product, "ProductVersion", "BizTalk Produktversion", view);
|
||||
AddRegistryValue(document, product, "ProductName", "BizTalk Produktname", view);
|
||||
AddRegistryValue(document, product, "Edition", "BizTalk Edition", view);
|
||||
var installPath = FirstRegistryValue(
|
||||
product,
|
||||
"InstallPath",
|
||||
"BizTalkServerInstallPath",
|
||||
"Path");
|
||||
if (!string.IsNullOrWhiteSpace(installPath)
|
||||
&& string.IsNullOrWhiteSpace(document.System.BizTalkInstallPath))
|
||||
if (product != null)
|
||||
{
|
||||
document.System.BizTalkInstallPath = installPath;
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"BizTalk Installationspfad",
|
||||
installPath,
|
||||
"Registry " + view));
|
||||
AddRegistryValue(document, product, "ProductVersion", "BizTalk Produktversion", view);
|
||||
AddRegistryValue(document, product, "ProductName", "BizTalk Produktname", view);
|
||||
AddRegistryValue(document, product, "Edition", "BizTalk Edition", view);
|
||||
var installPath = FirstRegistryValue(
|
||||
product,
|
||||
"InstallPath",
|
||||
"BizTalkServerInstallPath",
|
||||
"Path");
|
||||
if (!string.IsNullOrWhiteSpace(installPath)
|
||||
&& string.IsNullOrWhiteSpace(document.System.BizTalkInstallPath))
|
||||
{
|
||||
document.System.BizTalkInstallPath = installPath;
|
||||
document.System.Properties.Add(new NameValueRecord(
|
||||
"BizTalk Installationspfad",
|
||||
installPath,
|
||||
"Registry " + view));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view))
|
||||
using (var administration = baseKey.OpenSubKey(AdministrationKey, false))
|
||||
{
|
||||
if (administration == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(document.System.ManagementServer))
|
||||
{
|
||||
document.System.ManagementServer = FirstRegistryValue(
|
||||
administration,
|
||||
"MgmtDBServer",
|
||||
"ManagementDBServer");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(document.System.ManagementDatabase))
|
||||
{
|
||||
document.System.ManagementDatabase = FirstRegistryValue(
|
||||
administration,
|
||||
"MgmtDBName",
|
||||
"ManagementDBName");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view))
|
||||
using (var administration = baseKey.OpenSubKey(AdministrationKey, false))
|
||||
catch (Exception exception) when (IsRecoverableRegistryException(exception))
|
||||
{
|
||||
if (administration == null)
|
||||
document.Findings.Add(new Finding
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(document.System.ManagementServer))
|
||||
{
|
||||
document.System.ManagementServer = FirstRegistryValue(
|
||||
administration,
|
||||
"MgmtDBServer",
|
||||
"ManagementDBServer");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(document.System.ManagementDatabase))
|
||||
{
|
||||
document.System.ManagementDatabase = FirstRegistryValue(
|
||||
administration,
|
||||
"MgmtDBName",
|
||||
"ManagementDBName");
|
||||
}
|
||||
Severity = "Hinweis",
|
||||
Area = "BizTalk Registry " + view,
|
||||
Message = "BizTalk-Registryansicht konnte nicht gelesen werden: "
|
||||
+ exception.Message,
|
||||
RecommendedAction =
|
||||
"Berechtigungen prüfen; WMI oder explizite "
|
||||
+ "--management-Parameter können die Ermittlung übernehmen.",
|
||||
Owner = "Windows-/BizTalk-Betrieb"
|
||||
});
|
||||
logger.Exception(
|
||||
"BizTalk-Registryansicht " + view + " fehlgeschlagen",
|
||||
exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,64 +258,138 @@ namespace BizTalkSapEnvironmentInventory.Collectors
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectBizTalkGroupSetting(InventoryDocument document)
|
||||
private void CollectBizTalkGroupSetting(InventoryDocument document)
|
||||
{
|
||||
const string query =
|
||||
"SELECT Name,MgmtDbServerName,MgmtDbName FROM MSBTS_GroupSetting";
|
||||
var timer = Stopwatch.StartNew();
|
||||
logger.Detail(@"WMI-Namespace: \\.\root\MicrosoftBizTalkServer");
|
||||
logger.Detail("WQL: " + query);
|
||||
try
|
||||
{
|
||||
var scope = CreateBizTalkScope();
|
||||
logger.Info("Verbinde lokal mit dem BizTalk-WMI-Namespace.");
|
||||
scope.Connect();
|
||||
using (var searcher = new ManagementObjectSearcher(
|
||||
@"root\MicrosoftBizTalkServer",
|
||||
"SELECT Name,MgmtDbServerName,MgmtDbName,BizTalkAdministratorGroup,"
|
||||
+ "BizTalkOperatorGroup,BizTalkReadOnlyUserGroup,SSOServerName "
|
||||
+ "FROM MSBTS_GroupSetting"))
|
||||
scope,
|
||||
new ObjectQuery(query),
|
||||
CreateEnumerationOptions()))
|
||||
{
|
||||
foreach (ManagementObject item in searcher.Get())
|
||||
using (var rows = searcher.Get())
|
||||
{
|
||||
var managementServer = Value(item, "MgmtDbServerName");
|
||||
var managementDatabase = Value(item, "MgmtDbName");
|
||||
if (!string.IsNullOrWhiteSpace(managementServer))
|
||||
var count = 0;
|
||||
foreach (ManagementObject item in rows)
|
||||
{
|
||||
document.System.ManagementServer = managementServer;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(managementDatabase))
|
||||
{
|
||||
document.System.ManagementDatabase = managementDatabase;
|
||||
using (item)
|
||||
{
|
||||
count++;
|
||||
if (count != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var managementServer = Value(item, "MgmtDbServerName");
|
||||
var managementDatabase = Value(item, "MgmtDbName");
|
||||
if (!string.IsNullOrWhiteSpace(managementServer))
|
||||
{
|
||||
document.System.ManagementServer = managementServer;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(managementDatabase))
|
||||
{
|
||||
document.System.ManagementDatabase = managementDatabase;
|
||||
}
|
||||
|
||||
AddWmiValue(document, item, "Name", "BizTalk Gruppenname");
|
||||
}
|
||||
}
|
||||
|
||||
AddWmiValue(document, item, "Name", "BizTalk Gruppenname");
|
||||
AddWmiValue(
|
||||
document,
|
||||
item,
|
||||
"BizTalkAdministratorGroup",
|
||||
"BizTalk Administratorengruppe");
|
||||
AddWmiValue(
|
||||
document,
|
||||
item,
|
||||
"BizTalkOperatorGroup",
|
||||
"BizTalk Operatorengruppe");
|
||||
AddWmiValue(
|
||||
document,
|
||||
item,
|
||||
"BizTalkReadOnlyUserGroup",
|
||||
"BizTalk ReadOnly-Gruppe");
|
||||
AddWmiValue(document, item, "SSOServerName", "Enterprise SSO Server");
|
||||
break;
|
||||
timer.Stop();
|
||||
logger.Info("MSBTS_GroupSetting abgeschlossen: Datensätze="
|
||||
+ count + "; Dauer=" + timer.ElapsedMilliseconds + " ms.");
|
||||
if (count == 0)
|
||||
{
|
||||
AddGroupSettingFinding(
|
||||
document,
|
||||
"MSBTS_GroupSetting lieferte keinen Datensatz.");
|
||||
}
|
||||
else if (count > 1)
|
||||
{
|
||||
AddGroupSettingFinding(
|
||||
document,
|
||||
"MSBTS_GroupSetting lieferte "
|
||||
+ count
|
||||
+ " Datensätze; der erste Datensatz wurde verwendet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ManagementException exception)
|
||||
catch (Exception exception) when (IsRecoverableWmiException(exception))
|
||||
{
|
||||
document.Findings.Add(new Finding
|
||||
{
|
||||
Severity = "Hinweis",
|
||||
Area = "BizTalk GroupSetting",
|
||||
Message = "MSBTS_GroupSetting konnte für die Management-DB-Erkennung nicht gelesen werden: "
|
||||
+ exception.Message,
|
||||
RecommendedAction = "Registry-Ergebnis prüfen oder --management-server explizit angeben.",
|
||||
Owner = "BizTalk-Betrieb"
|
||||
});
|
||||
timer.Stop();
|
||||
AddGroupSettingFinding(
|
||||
document,
|
||||
"MSBTS_GroupSetting konnte für die Management-DB-Erkennung "
|
||||
+ "nicht gelesen werden: " + exception.Message);
|
||||
logger.Exception("MSBTS_GroupSetting fehlgeschlagen", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private ManagementScope CreateBizTalkScope()
|
||||
{
|
||||
var scope = new ManagementScope(@"\\.\root\MicrosoftBizTalkServer");
|
||||
scope.Options.Timeout = timeout;
|
||||
scope.Options.EnablePrivileges = false;
|
||||
scope.Options.Impersonation = ImpersonationLevel.Impersonate;
|
||||
return scope;
|
||||
}
|
||||
|
||||
private EnumerationOptions CreateEnumerationOptions()
|
||||
{
|
||||
return new EnumerationOptions
|
||||
{
|
||||
ReturnImmediately = false,
|
||||
Rewindable = false,
|
||||
Timeout = timeout
|
||||
};
|
||||
}
|
||||
|
||||
private void ConfigureSearcher(ManagementObjectSearcher searcher)
|
||||
{
|
||||
searcher.Options.ReturnImmediately = false;
|
||||
searcher.Options.Rewindable = false;
|
||||
searcher.Options.Timeout = timeout;
|
||||
}
|
||||
|
||||
private static void AddGroupSettingFinding(
|
||||
InventoryDocument document,
|
||||
string message)
|
||||
{
|
||||
document.Findings.Add(new Finding
|
||||
{
|
||||
Severity = "Hinweis",
|
||||
Area = "BizTalk GroupSetting",
|
||||
Message = message,
|
||||
RecommendedAction =
|
||||
"Registry-Ergebnis prüfen oder --management-server und "
|
||||
+ "--management-database explizit angeben.",
|
||||
Owner = "BizTalk-Betrieb"
|
||||
});
|
||||
}
|
||||
|
||||
private static bool IsRecoverableWmiException(Exception exception)
|
||||
{
|
||||
return exception is ManagementException
|
||||
|| exception is COMException
|
||||
|| exception is UnauthorizedAccessException;
|
||||
}
|
||||
|
||||
private static bool IsRecoverableRegistryException(Exception exception)
|
||||
{
|
||||
return exception is IOException
|
||||
|| exception is SecurityException
|
||||
|| exception is UnauthorizedAccessException;
|
||||
}
|
||||
|
||||
private static void AddWmiValue(
|
||||
InventoryDocument document,
|
||||
ManagementBaseObject item,
|
||||
|
||||
Reference in New Issue
Block a user