diff --git a/Dokumentation.md b/Dokumentation.md
index 00623f5..d047ecc 100644
--- a/Dokumentation.md
+++ b/Dokumentation.md
@@ -1,220 +1,240 @@
-# Technische Dokumentation: BEW BizTalk Application Catalog
+# Technische Dokumentation: BEW BizTalk Application Catalog – Phase 1
-## 1. Zielbild
+## 1. Ziel und Abgrenzung
-Das Werkzeug erstellt je Umgebung eine eigenständige Microsoft-Excel-Arbeitsmappe mit der vollständigen Liste der auf dem lokalen BizTalk Server 2020 installierten Anwendungen und den wichtigsten zugeordneten Kernparametern.
+Das Werkzeug bildet ausschließlich die Phase-1-Sicht `BizTalk Anwendungen & Adapter` ab. Das fachliche Ergebnis ist ein einblättriger ACC/PRD-Katalog mit:
+
+1. BizTalk-Anwendung
+2. Umgebung
+3. Adapter-Typ und Anzahl
+4. Endpunktanzahl
+5. Vorkommen in ACC
+6. Vorkommen in PRD
+7. Hinweis bei einseitigem Vorkommen
+
+Es ist kein technisches Vollinventar. Frühere Detailbereiche zu System, SQL, Status, Ports, Orchestrierungen, Schemas, Maps, Pipelines, Assemblies, Hosts, Handlern, Abdeckung und Findings sind nicht Bestandteil der XLSX und werden nicht mehr erhoben.
+
+## 2. Verteilte Erfassung
+
+ACC und PROD besitzen jeweils einen lokalen BizTalk Server 2020. Ein Prozess auf einem Server soll die andere Umgebung nicht remote abfragen.
```text
-ACC
- +-- 1 BizTalk Server 2020 / Windows Server 2019 <-- Tool lokal ausführen
- +-- 1 SQL Server für die BizTalk-Datenbanken
-
-PROD
- +-- 1 BizTalk Server 2020 / Windows Server 2019 <-- Tool lokal ausführen
- +-- 1 SQL Server für die BizTalk-Datenbanken
+ACC BizTalk Server PROD BizTalk Server
+ | |
+ | lokales WMI | lokales WMI
+ v v
+ ACC JSON + lokale XLSX PROD JSON + lokale XLSX
+ \ /
+ \ /
+ +---- Merge auf beliebigem -----+
+ Windows-Rechner
+ |
+ v
+ gemeinsame ACC/PRD-XLSX
```
-ACC und PROD werden getrennt inventarisiert. Da es pro Umgebung nur einen BizTalk-Knoten gibt, ist kein Node-Abgleich erforderlich.
+Der JSON-Snapshot ist das kleine Austauschformat zwischen den getrennten Erfassungen. Er enthält weder Endpunktadressen noch Credentials.
-## 2. Architektur
+## 3. Komponenten
```text
-Administrative cmd.exe
- |
- +-- run-inventory.cmd ACC|PROD
- |
- +-- BizTalkApplicationCatalog.exe
- |
- +-- SystemCollector
- | +-- Win32_OperatingSystem
- | +-- lokale BizTalk Registry
- | +-- MSBTS_GroupSetting
- |
- +-- BizTalkWmiCollector
- | +-- vollständige Anwendungsliste
- | +-- Artefaktdetails
- | +-- Hosts und Handler
- | +-- Abdeckungsstatus pro Klasse
- |
- +-- XlsxReportWriter
- +-- Office Open XML / ZIP
- +-- Inline Strings, keine Shared-String-Abhängigkeit
- +-- Filter, Freeze Panes, Styles
- +-- atomarer Dateiaustausch
+CommandLineOptions
+ +-- validiert lokalen Modus oder Merge-Modus
+
+BizTalkWmiCollector
+ +-- MSBTS_Application
+ +-- MSBTS_ReceivePort
+ +-- MSBTS_SendPort
+ +-- MSBTS_ReceiveLocation
+
+SnapshotStore
+ +-- normalisiert je Anwendung Adapterzählungen
+ +-- schreibt/liest DataContract-JSON
+ +-- validiert Schema, Summen, Umgebung und Vollständigkeit
+
+XlsxReportWriter
+ +-- genau ein Blatt "Phase 1"
+ +-- Office Open XML ohne Office-Interop
+ +-- Titel, Filter, Freeze Pane und Summenzeile
```
-Die Anwendung referenziert keine `Microsoft.BizTalk.*`-Assembly. Die einzige BizTalk-Schnittstelle ist der lokal installierte WMI-Provider. Dadurch besteht das Deployment nur aus EXE, Konfiguration, Startskript und Dokumentation.
+## 4. WMI-Datenmodell
-## 3. Toolchain und Kompatibilität
+### 4.1 Anwendungen
-Die Build-Baseline ist absichtlich auf die BizTalk-2020-Umgebung ausgerichtet:
+`MSBTS_Application` ist die Pflichtquelle der Anwendungsliste. Verwendet wird nur `Name` beziehungsweise `ApplicationName`.
-- Visual Studio 2019 / Solution Version 16
-- MSBuild 16.x, insbesondere 16.11
-- klassisches MSBuild-Projektformat mit `ToolsVersion="15.0"`
+Die Abfrage muss mindestens eine Anwendung liefern. Andernfalls ist der lokale Lauf unvollständig.
+
+### 4.2 Receive-Endpunkte
+
+Eine `MSBTS_ReceiveLocation` zählt als ein Endpunkt. Der Adapter wird defensiv aus `AdapterName`, `TransportType` oder `PTTransportType` gelesen.
+
+Da eine Receive Location abhängig vom WMI-Provider keine direkte `ApplicationName` liefern kann, wird vorher `MSBTS_ReceivePort` gelesen. Über `ReceivePortName` wird die Anwendung aufgelöst. Ein Receive Port zählt selbst nicht als Endpunkt.
+
+### 4.3 Send-Endpunkte
+
+Bei `MSBTS_SendPort` zählt die primäre Transportkonfiguration als ein Endpunkt. Ist eine sekundäre Transportkonfiguration vorhanden, zählt sie als zusätzlicher Endpunkt.
+
+Primärer Adapter:
+
+- `PTTransportType`
+- Fallback `PrimaryTransportType`
+- Fallback `AdapterName`
+- Fallback `TransportType`
+
+Sekundärer Adapter:
+
+- `STTransportType`
+- Fallback `SecondaryTransportType`
+
+Fehlt ein gelieferter Adaptername, wird `Unbekannt` verwendet. Ein Endpunkt ohne Anwendungszuordnung macht den Lauf unvollständig, weil er sonst in der Anwendungssicht verloren ginge.
+
+## 5. Snapshot-Format
+
+Das JSON enthält nur normalisierte Katalogdaten:
+
+```json
+{
+ "SchemaVersion": 1,
+ "EnvironmentName": "ACC",
+ "ComputerName": "BIZTALK-ACC",
+ "CreatedUtc": "2026-07-27T13:00:00.0000000Z",
+ "IsComplete": true,
+ "Applications": [
+ {
+ "Name": "ExampleApplication",
+ "EndpointCount": 2,
+ "AdapterCounts": [
+ { "AdapterType": "FILE", "Count": 1 },
+ { "AdapterType": "SFTP", "Count": 1 }
+ ]
+ }
+ ]
+}
+```
+
+Vor einem Merge werden geprüft:
+
+- `SchemaVersion` ist `1`
+- erwartete Umgebung ist exakt `ACC` beziehungsweise `PROD`
+- `IsComplete` ist `true`
+- Namen und Adaptertypen sind nicht leer
+- Zählwerte sind nicht negativ
+- Summe der Adapterzählungen entspricht `EndpointCount`
+
+JSON und XLSX werden über eine temporäre Datei geschrieben und erst nach erfolgreichem Abschluss auf den endgültigen Dateinamen verschoben.
+
+## 6. Merge-Regeln
+
+Anwendungsnamen werden ohne Beachtung der Groß-/Kleinschreibung verglichen. Für die Anzeige wird bei einer gemeinsamen Anwendung bevorzugt die Schreibweise aus ACC verwendet.
+
+| Situation | Umgebung | ACC | PRD | Hinweis |
+| --- | --- | --- | --- | --- |
+| in beiden vorhanden | `ACC + PRD` | `✓` | `✓` | leer |
+| nur ACC | `nur ACC` | `✓` | `–` | `Nur in ACC vorhanden` |
+| nur PROD | `nur PRD` | `–` | `✓` | `Nur in PRD vorhanden – nicht in ACC` |
+
+Die Endpunktanzahl einer gemeinsamen Zeile ist die Summe beider Umgebungen.
+
+Sind die Adapterzählungen identisch, erscheint nur eine kompakte Darstellung:
+
+```text
+FILE (1x) / SFTP (1x)
+```
+
+Bei einer Abweichung bleiben beide Nachweise sichtbar:
+
+```text
+ACC: FILE (2x) | PRD: FILE (1x) / SFTP (1x)
+```
+
+Damit wird keine Übereinstimmung suggeriert, wenn lediglich die Gesamtzahl gleich ist.
+
+## 7. Excel-Aufbau
+
+Die Arbeitsmappe enthält genau:
+
+```text
+xl/worksheets/sheet1.xml -> Blatt "Phase 1"
+```
+
+Das Blatt besteht aus:
+
+- Zeile 1: zusammengeführter Titel
+- Zeile 2: sieben Spaltenüberschriften
+- ab Zeile 3: alphabetisch sortierte Anwendungen
+- letzte Zeile: zusammengeführte Summenzeile
+
+Der Filter umfasst nur Kopf- und Datenzeilen, nicht die Summenzeile. Die ersten beiden Zeilen sind fixiert. Zelltexte werden als `inlineStr` gespeichert. Office und COM-Interop sind nicht erforderlich.
+
+## 8. Fehlerverhalten
+
+Alle vier WMI-Abfragen bilden einen Pflichtabschnitt. Ein Fehler führt zu:
+
+- Exitcode `1`
+- Logeintrag
+- JSON mit `IsComplete: false`
+- lokaler XLSX auf Basis der bis dahin ermittelten Daten
+
+Der Merge lehnt einen solchen JSON-Snapshot ab. Dadurch werden technische Lücken nicht als bestätigte Nullwerte in den ACC/PRD-Katalog übernommen.
+
+Ungültige Parameter, fehlende Dateien, fehlerhaftes JSON und Schreibfehler liefern Exitcode `2`.
+
+## 9. Sicherheit
+
+- ausschließlich lesende lokale WMI-Abfragen
+- keine Änderungen an BizTalk-Konfiguration oder Runtime
+- keine SQL-Abfragen
+- keine Endpunktadressen
+- keine Binding-Exporte
+- keine Credentials, Secrets oder Tokens
+- keine Netzwerkverbindungen zu fachlichen Endpunkten
+
+Anwendungsnamen, Servernamen und Adapterverteilungen bleiben interne Betriebsinformationen. JSON, XLSX und Log sind geschützt abzulegen.
+
+## 10. Build und Test
+
+Baseline:
+
+- Visual Studio 2019 / MSBuild 16.x
+- klassisches MSBuild-Projektformat
- .NET Framework 4.7.2
- C# 7.3
-- keine SDK-Style-Projekte
-- kein `PackageReference`
-- keine `global.json`
-- keine NuGet-Abhängigkeit
-
-Damit wird nicht das installierte .NET SDK 8 oder neuer ausgewählt. Der bekannte Fehler „.NET SDK 8.x requires at least MSBuild 17.8.3“ kann bei dieser Solution nicht durch eine SDK-Auswahl entstehen.
-
-## 4. Datenquellen
-
-### 4.1 Pflichtquelle
-
-`MSBTS_Application` liefert die Primärliste aller Anwendungen. Liefert diese Klasse keine Datensätze oder kann sie nicht gelesen werden, gilt der Pflichtabschnitt als fehlgeschlagen und der Prozess endet nach der dennoch versuchten XLSX-Erzeugung mit Exitcode `1`.
-
-Aufgenommene Parameter:
-
-- `Name` beziehungsweise `ApplicationName`
-- `Description`
-- `Status`
-- `IsDefault`, soweit vom Provider geliefert
-
-### 4.2 Optionale Artefaktklassen
-
-| WMI-Klasse | Berichtstyp |
-| --- | --- |
-| `MSBTS_Orchestration` | Orchestrierung |
-| `MSBTS_SendPort` | Send Port |
-| `MSBTS_SendPortGroup` | Send Port Group |
-| `MSBTS_ReceivePort` | Receive Port |
-| `MSBTS_ReceiveLocation` | Receive Location |
-| `MSBTS_Assembly` | Assembly |
-| `MSBTS_Schema` | Schema |
-| `MSBTS_Map` | Map |
-| `MSBTS_Pipeline` | Pipeline |
-
-Die WMI-Klassen können abhängig von Installation, Providerstand und Berechtigung unterschiedliche Properties anbieten. Deshalb fragt der Collector `SELECT *` ab und liest bekannte Properties defensiv. Eine nicht vorhandene Property wird leer gelassen und beendet die Klasse nicht.
-
-Receive Ports werden vor Receive Locations gelesen. Fehlt an einer Receive Location die direkte `ApplicationName`, wird die Anwendung über `ReceivePortName` bestmöglich aufgelöst.
-
-### 4.3 Hosts und Handler
-
-- `MSBTS_HostSetting`
-- `MSBTS_HostInstance`
-- `MSBTS_ReceiveHandler`
-- `MSBTS_SendHandler2`
-- Fallback `MSBTS_SendHandler`
-
-Erfasst werden Name, Server, Status, Hosttyp, Windows-Gruppe, 32-Bit-Kennzeichen, Trusted-Kennzeichen und Adaptername, soweit vorhanden.
-
-### 4.4 Systeminformationen
-
-- `Win32_OperatingSystem`
-- `HKLM\SOFTWARE\Microsoft\BizTalk Server\3.0`
-- `HKLM\SOFTWARE\Microsoft\BizTalk Server\3.0\Administration`
-- `MSBTS_GroupSetting`
-
-Registry-Werte werden in 64- und 32-Bit-Ansicht gelesen. Kommandozeilenwerte für Management Server und Datenbank überschreiben ermittelte Werte.
-
-## 5. Abdeckungsmodell
-
-Jede abgefragte BizTalk-WMI-Klasse erzeugt einen Datensatz im Blatt `Abdeckung`:
-
-| Status | Bedeutung |
-| --- | --- |
-| `Vollständig` | Abfrage erfolgreich; die angegebene Zeilenzahl ist technisch belegt |
-| `Begrenzt` | Abfrage erfolgreich, aber das konfigurierte Zeilenlimit wurde erreicht |
-| `Nicht verfügbar` | Klasse oder Berechtigung nicht verfügbar; eine Null ist nicht fachlich bestätigt |
-| `Fehler` | Pflichtquelle lieferte kein verwertbares Ergebnis |
-
-Dieses Modell verhindert die irreführende Interpretation eines fehlenden WMI-Ergebnisses als „keine Artefakte vorhanden“.
-
-`MaxRowsPerArtifactType` begrenzt optional die Details pro Artefakttyp. Der Standard ist `10000`. Die Anwendungsliste aus `MSBTS_Application` wird nicht begrenzt.
-
-## 6. Excel-Erzeugung
-
-Die `.xlsx`-Datei ist ein OPC-/ZIP-Paket mit folgenden Kernteilen:
-
-```text
-[Content_Types].xml
-_rels/.rels
-docProps/core.xml
-docProps/app.xml
-xl/workbook.xml
-xl/_rels/workbook.xml.rels
-xl/styles.xml
-xl/worksheets/sheet1.xml ... sheet10.xml
-```
-
-Zelltexte werden als `inlineStr` geschrieben. Dadurch wird keine Shared-String-Tabelle im Arbeitsspeicher aufgebaut. Zahlen werden als numerische Zellen gespeichert und können in Excel direkt summiert oder gefiltert werden.
-
-Der Writer:
-
-1. erzeugt eine eindeutige temporäre Datei im Zielordner,
-2. schreibt und schließt alle XML-/ZIP-Teile,
-3. entfernt eine gegebenenfalls vorhandene Zieldatei gleichen Namens,
-4. verschiebt die vollständige temporäre Datei atomar auf den Zielnamen,
-5. löscht temporäre Reste auch im Fehlerfall.
-
-Ein einzelner Zelltext wird auf das Excel-Limit von 32.767 Zeichen begrenzt. Nicht XML-konforme Steuerzeichen werden entfernt.
-
-## 7. Resilienz
-
-- `SafeCollector` isoliert voneinander unabhängige Abschnitte.
-- Jeder Abschnitt schreibt Start, Ende, Dauer und Fehler in Konsole und Log.
-- Optionale WMI-Klassen werden einzeln behandelt.
-- Timeout und maximale Detailzeilen sind in `App.config` konfigurierbar.
-- Die XLSX wird auch bei optionalen Lücken erstellt.
-- Die vollständige Anwendungsliste ist ein Pflichtabschnitt.
-- Findings erklären Lücken und nennen eine konkrete Prüfung.
-
-## 8. Datenschutz und Secrets
-
-Das Inventar soll keine Credentials enthalten. Bekannte Kennwort-, Secret- und Tokenmuster in Text- und Adresswerten werden durch `[REDACTED]` ersetzt. Das ersetzt keine Schutzklassifizierung: interne Adressen, Servernamen, Hostgruppen und Anwendungsbezeichnungen bleiben sensible Betriebsinformationen.
-
-Es werden keine Kennwörter abgefragt, keine Bindings exportiert und keine aktiven Endpunktverbindungen getestet.
-
-## 9. Build, Test und Paketierung
-
-Windows-Build:
+- keine NuGet-Pakete
+- kein .NET SDK erforderlich
```cmd
scripts\build-release.cmd
```
-Der Build:
+Der Self-Test benötigt kein BizTalk und prüft:
-1. findet MSBuild über `vswhere.exe` oder `PATH`,
-2. baut `Release|Any CPU`,
-3. führt das Testprogramm aus,
-4. führt den Self-Test der eigentlichen EXE aus.
+- JSON-Schreiben und -Lesen
+- Snapshot-Validierung
+- ACC/PRD-Union
+- Adapteraggregation
+- Endpunktsummen
+- ein einziges Blatt `Phase 1`
+- erforderliche OPC-/XLSX-Teile
+- XML-Wohlgeformtheit
+- Titel- und Summen-Merges
+- korrekten Filterbereich
-Der Self-Test benötigt kein BizTalk. Er prüft:
-
-- Secret-Redaktion
-- Erstellung aller zehn Tabellenblätter
-- Vorhandensein der erforderlichen OPC-/XLSX-Teile
-- XML-Wohlgeformtheit aller Paketbestandteile
-- erwartete Blattnamen
-- Abwesenheit des Testkennworts
-
-Deployment:
-
-```cmd
-scripts\package-release.cmd
-```
-
-Quell-ZIP und certutil-dekodierbarer Text:
-
-```cmd
-scripts\package-source.cmd
-```
-
-## 10. Validierung in ACC und PROD
+## 11. Betriebsvalidierung
Je Umgebung:
-1. EXE mit `--self-test` starten.
-2. Inventar in einer administrativen `cmd.exe` ausführen.
-3. Exitcode und Log prüfen.
-4. XLSX öffnen und Blatt `Abdeckung` prüfen.
-5. Zahl der Anwendungen mit der BizTalk Administration Console vergleichen.
-6. Stichproben für Ports, Orchestrierungen und Assemblies durchführen.
-7. XLSX und Log im geschützten Umgebungsordner archivieren.
+1. `--self-test` erfolgreich ausführen.
+2. Lokalen Lauf in administrativer `cmd.exe` starten.
+3. Exitcode `0` und Log prüfen.
+4. Anwendungsgesamtzahl mit der BizTalk Administration Console vergleichen.
+5. Send Ports, sekundäre Transporte und Receive Locations stichprobenartig zählen.
+6. Nur die vollständige JSON-Datei für den Merge verwenden.
-ACC- und PROD-Dateien dürfen nicht zusammengeführt werden, ohne die Spalten `Umgebung` und `Server` beizubehalten.
+Nach dem Merge:
+
+1. Summen für ACC und PROD mit den lokalen Dateien vergleichen.
+2. Anwendungen mit `nur ACC` und `nur PRD` fachlich prüfen.
+3. Abweichend beschriftete ACC-/PRD-Adapterverteilungen prüfen.
+4. Ergebnis geschützt archivieren.
diff --git a/Readme.md b/Readme.md
index 3189884..c6ecc83 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,82 +1,61 @@
-# BEW BizTalk Application Catalog
+# BEW BizTalk Application Catalog – Phase 1
-`BEW BizTalk Application Catalog` inventarisiert die auf einem BizTalk Server 2020 installierten Anwendungen und erzeugt eine kompakte, filterbare Microsoft-Excel-Arbeitsmappe (`.xlsx`).
+Das Tool erzeugt nur die für die Phase-1-Excel-Sicht benötigten Daten:
-Das Tool wird lokal einmal auf dem BizTalk-Server in `ACC` und einmal auf dem BizTalk-Server in `PROD` ausgeführt. Beide Umgebungen bestehen jeweils aus:
-
-- einem BizTalk Server 2020 auf Windows Server 2019
-- einem separaten SQL Server für die BizTalk-Datenbanken
-
-Microsoft Excel, Microsoft Office, PowerShell, Internetzugriff und ein .NET SDK werden auf dem Zielserver nicht benötigt.
-
-## Ergebnis
-
-Die erzeugte Arbeitsmappe enthält zehn Tabellenblätter:
-
-| Blatt | Inhalt |
+| Spalte | Inhalt |
| --- | --- |
-| `Übersicht` | Umgebung, Server, BizTalk-/Windows-Metadaten, Gesamtzahlen und Laufstatus |
-| `Anwendungen` | vollständige, kompakte Anwendungsliste mit Status, Beschreibung und Artefaktzahlen |
-| `Artefakte` | konsolidierte technische Detailansicht |
-| `Ports` | Send Ports, Send Port Groups, Receive Ports und Receive Locations |
-| `Orchestrierungen` | Orchestrierungen, Status und Hostzuordnung |
-| `Schemas-Maps-Pipelines` | Schemas, Maps und Pipelines |
-| `Assemblies` | bereitgestellte BizTalk-Assemblies |
-| `Hosts-Handler` | Hosts, Hostinstanzen sowie Receive-/Send-Handler |
-| `Abdeckung` | Erfolg, Zeilenzahl und mögliche Lücken jeder WMI-Datenquelle |
-| `Findings` | Warnungen, Fehler und empfohlene Prüfungen |
+| `BizTalk-Anwendung` | Name der BizTalk-Anwendung |
+| `Umgebung` | `ACC + PRD`, `nur ACC` oder `nur PRD` |
+| `Adapter-Typ` | Adapter mit Anzahl, zum Beispiel `FILE (2x) / SFTP (1x)` |
+| `Anzahl Endpunkte` | Summe der Endpunkte in den berücksichtigten Umgebungen |
+| `BizTalk-Anwendung in ACC` | `✓` oder `–` |
+| `BizTalk-Anwendung in PRD` | `✓` oder `–` |
+| `Hinweis` | Kennzeichnung einer nur einseitig vorhandenen Anwendung |
-Alle Detailblätter besitzen Filter, fixierte Kopfzeilen und angepasste Spaltenbreiten.
+Die Arbeitsmappe enthält exakt ein Blatt namens `Phase 1`. Es werden keine weiteren Übersichts-, Artefakt-, Port-, Host-, Abdeckungs- oder Findings-Blätter erzeugt.
-## Kernparameter je Anwendung
+## Ablauf
-Das Blatt `Anwendungen` enthält unter anderem:
+ACC und PROD sind getrennte BizTalk-Umgebungen. Deshalb arbeitet das Tool in zwei Schritten:
-- Umgebung und ausführenden BizTalk Server
-- Anwendungsname, Beschreibung, Status und Standardanwendungskennzeichen
-- Gesamtzahl zugeordneter Artefakte
-- Anzahl Orchestrierungen
-- Anzahl Send Ports und Send Port Groups
-- Anzahl Receive Ports und Receive Locations
-- Anzahl Assemblies, Schemas, Maps und Pipelines
-- erkannte Hosts beziehungsweise Handler
-- verwendete Adapter
-- expliziten Status der Detailabdeckung
+1. Auf dem lokalen ACC-BizTalk-Server wird ein ACC-JSON-Snapshot erzeugt.
+2. Auf dem lokalen PROD-BizTalk-Server wird ein PROD-JSON-Snapshot erzeugt.
+3. Beide JSON-Dateien werden mit demselben Tool zur gemeinsamen Excel-Sicht zusammengeführt.
-Die vollständige Anwendungsliste stammt aus `MSBTS_Application`. Eine nicht verfügbare optionale Artefaktklasse wird nicht stillschweigend als fachliche Null interpretiert, sondern im Blatt `Abdeckung` ausgewiesen.
+Jeder lokale Lauf erzeugt zusätzlich eine einblättrige Excel-Sicht für die jeweilige Umgebung. Erst der Merge liefert den belastbaren ACC/PRD-Vergleich wie in der Zielansicht.
-## Sicherheits- und Betriebsprinzip
+## Erfasste Daten
-- ausschließlich lokale, lesende WMI- und Registry-Abfragen
-- keine Änderungen an Anwendungen, Ports, Hosts oder Runtime-Instanzen
-- keine direkte SQL-Abfrage und keine Datenbankänderung
-- keine Office-Automation und keine COM-Interop
-- zusätzliche Redigierung versehentlich gelieferter Kennwort-/Tokenwerte
-- atomare XLSX-Erzeugung über eine temporäre Datei
-- Fehler optionaler WMI-Klassen stoppen die übrige Erfassung nicht
-- identische Fortschrittsausgabe auf Konsole und in der Logdatei
+Das Tool liest ausschließlich:
-Die XLSX- und Logdatei enthält interne Server-, Anwendungs-, Host- und Endpunktinformationen und muss entsprechend geschützt abgelegt werden.
+- `MSBTS_Application` für die vollständige Anwendungsliste
+- `MSBTS_SendPort` für primäre und gegebenenfalls sekundäre Send-Endpunkte
+- `MSBTS_ReceivePort` nur zur Zuordnung einer Receive Location zur Anwendung
+- `MSBTS_ReceiveLocation` für Receive-Endpunkte
-## Voraussetzungen auf ACC und PROD
+Ein Endpunkt ist:
-- lokale Ausführung auf dem jeweiligen BizTalk Server 2020
-- Windows Server 2019
-- administrative `cmd.exe` empfohlen
-- Konto mit Leserechten auf `root\MicrosoftBizTalkServer`, regulär ein BizTalk-Administratoren- oder geeignetes Operatorenkonto
+- die primäre Transportkonfiguration eines Send Ports,
+- eine konfigurierte sekundäre Transportkonfiguration eines Send Ports oder
+- eine Receive Location.
+
+Receive Ports selbst sind Container und werden nicht als Endpunkt gezählt. Anwendungen ohne Endpunkt bleiben mit `0` und Adapter-Typ `–` in der Sicht enthalten.
+
+Nicht erfasst werden insbesondere Adressen, Credentials, Beschreibungen, Status, Hosts, Handler, Orchestrierungen, Schemas, Maps, Pipelines, Assemblies, Betriebssystem- oder SQL-Daten.
+
+## Voraussetzungen
+
+- BizTalk Server 2020 auf Windows Server 2019
+- lokale Ausführung auf dem jeweiligen BizTalk-Server
- .NET Framework 4.7.2 oder höher
-- funktionierender lokaler BizTalk-WMI-Provider
+- Leserechte auf `root\MicrosoftBizTalkServer`
+- administrative `cmd.exe` empfohlen
-Microsoft Office ist ausdrücklich keine Voraussetzung.
+Microsoft Excel, Microsoft Office, PowerShell, Internetzugriff, NuGet und ein .NET SDK werden auf dem Zielserver nicht benötigt.
-## Schnellstart
+## Lokalen Snapshot erzeugen
-1. Deployment-Ordner auf den BizTalk Server kopieren.
-2. Administrative `cmd.exe` öffnen.
-3. Self-Test ohne BizTalk-Zugriff ausführen.
-4. Inventar für die jeweilige Umgebung erzeugen.
-
-Self-Test:
+Zuerst den Self-Test ausführen:
```cmd
BizTalkApplicationCatalog.exe --self-test
@@ -94,117 +73,95 @@ PROD:
run-inventory.cmd PROD C:\BizTalk-Doku\PROD
```
+Ergebnis eines erfolgreichen lokalen Laufs:
+
+```text
+Phase1-BizTalk-Anwendungskatalog-ACC-SERVER-20260727-150000.json
+Phase1-BizTalk-Anwendungskatalog-ACC-SERVER-20260727-150000.xlsx
+Phase1-BizTalk-Anwendungskatalog-ACC-SERVER-20260727-150000.log
+```
+
+Nur JSON-Dateien eines Laufs mit Exitcode `0` dürfen zusammengeführt werden. Ein unvollständiger Snapshot trägt `IsComplete: false` und wird vom Merge abgelehnt.
+
+## ACC und PROD zusammenführen
+
+Beide JSON-Dateien in einen gemeinsamen, geschützten Ordner kopieren und ausführen:
+
+```cmd
+run-merge.cmd ^
+ C:\BizTalk-Doku\ACC\Phase1-BizTalk-Anwendungskatalog-ACC-SERVER-20260727-150000.json ^
+ C:\BizTalk-Doku\PROD\Phase1-BizTalk-Anwendungskatalog-PROD-SERVER-20260727-151500.json ^
+ C:\BizTalk-Doku\ACC-PROD
+```
+
Direkter Aufruf:
```cmd
BizTalkApplicationCatalog.exe ^
- --environment ACC ^
- --output C:\BizTalk-Doku\ACC
+ --merge ^
+ --acc-json C:\BizTalk-Doku\ACC\ACC.json ^
+ --prod-json C:\BizTalk-Doku\PROD\PROD.json ^
+ --output C:\BizTalk-Doku\ACC-PROD
```
-## Konsolenausgabe
-
-Das Tool zeigt laufend, was es gerade erfasst und wann die Excel-Datei geschrieben wurde:
+Die gemeinsame Datei heißt beispielsweise:
```text
-[INFO] Starte Abschnitt: Anwendungen und Artefakte
-[INFO] 34 installierte BizTalk-Anwendung(en) gefunden.
-[INFO] Send Port: 87 Datensatz/Datensätze.
-[INFO] Erzeuge Microsoft-Excel-Datei: C:\BizTalk-Doku\ACC\...
-[INFO] Excel-Datei erfolgreich erzeugt: C:\BizTalk-Doku\ACC\...
+Phase1-BizTalk-Anwendungskatalog-ACC-PROD-20260727-153000.xlsx
```
-## Ausgabedateien
+Bei identischer Adapterverteilung in ACC und PROD wird sie einmal angezeigt. Bei Abweichungen kennzeichnet die Zelle beide Werte, zum Beispiel:
```text
-BizTalk-Anwendungsinventar-ACC-BIZTALKSERVER-20260727-150000.xlsx
-BizTalk-Anwendungsinventar-ACC-BIZTALKSERVER-20260727-150000.log
+ACC: FILE (2x) | PRD: FILE (1x) / SFTP (1x)
```
+`Anzahl Endpunkte` ist im Merge die Summe aus ACC und PROD.
+
## Optionen und Exitcodes
| Option | Bedeutung |
| --- | --- |
-| `--environment NAME` | Umgebung, regulär `ACC` oder `PROD` |
-| `--output PFAD` | Zielordner für XLSX und Log |
-| `--management-server NAME` | optionaler Management-SQL-Server-Hinweis |
-| `--management-database NAME` | optionale Management-Datenbank; Fallback `BizTalkMgmtDb` |
-| `--self-test` | prüft XLSX-Struktur, Tabellen und Secret-Redaktion |
-| `--help` | zeigt die Hilfe |
+| `--environment ACC\|PROD` | lokaler Inventarlauf |
+| `--output PFAD` | Zielordner |
+| `--merge` | ACC- und PROD-Snapshot zusammenführen |
+| `--acc-json PFAD` | vollständiger ACC-Snapshot |
+| `--prod-json PFAD` | vollständiger PROD-Snapshot |
+| `--self-test` | JSON-, Merge- und XLSX-Test ohne BizTalk |
+| `--help` | Hilfe |
| Exitcode | Bedeutung |
| ---: | --- |
-| `0` | vollständige Anwendungserfassung und XLSX erfolgreich |
-| `1` | XLSX erzeugt, aber ein Pflichtabschnitt war unvollständig |
-| `2` | Aufruf-, Ausgabe- oder Berichtserzeugungsfehler |
+| `0` | Snapshot beziehungsweise Merge vollständig erzeugt |
+| `1` | lokaler Pflichtabschnitt unvollständig; JSON nicht mergen |
+| `2` | Aufruf-, Datei-, JSON- oder XLSX-Fehler |
-## Build mit Visual Studio 2019
+## Build
-Die Solution vermeidet bewusst den beim früheren IIS Inventory aufgetretenen .NET-SDK-/MSBuild-Konflikt:
-
-| Komponente | Vorgabe |
-| --- | --- |
-| Ziel | .NET Framework 4.7.2 |
-| Sprache | C# 7.3 |
-| Solution | Visual Studio 2019, Formatversion 16 |
-| Projektformat | klassisches MSBuild mit `ToolsVersion="15.0"` |
-| MSBuild | 16.x, einschließlich 16.11 |
-| NuGet | keine Pakete und kein Restore |
-| .NET SDK / `global.json` | nicht erforderlich |
-
-Voraussetzung auf dem Buildrechner ist das `.NET Framework 4.7.2 Developer/Targeting Pack`.
+Die Solution verwendet das klassische MSBuild-Projektformat für Visual Studio 2019 / MSBuild 16.x, .NET Framework 4.7.2 und C# 7.3. Es gibt keine NuGet-Abhängigkeiten.
```cmd
scripts\build-release.cmd
scripts\package-release.cmd
```
-Das Deployment liegt anschließend unter:
-
-```text
-artifacts\BizTalkApplicationCatalog-deploy\
-```
-
-## Quellpaket und Base64-Text
-
-Für eine dateibasierte Übergabe:
+## Quellpaket als certutil-Text
```cmd
scripts\package-source.cmd
```
-Erzeugt werden:
+Erzeugt:
```text
artifacts\BizTalkApplicationCatalog-source.zip
artifacts\BizTalkApplicationCatalog-source.zip.txt
```
-Dekodieren unter Windows:
+Dekodieren:
```cmd
certutil -decode BizTalkApplicationCatalog-source.zip.txt BizTalkApplicationCatalog-source.zip
```
-## Gitea
-
-Das Repository enthält `.gitea/workflows/build.yml`. Ein Windows-Runner mit Visual Studio 2019 Build Tools und .NET Framework 4.7.2 Developer Pack baut die Solution, führt Tests und Self-Test aus und stellt den Deployment-Ordner als Artefakt bereit.
-
-## Troubleshooting
-
-### Solution lässt sich in VS 2019 nicht öffnen
-
-Prüfen, dass wirklich diese klassische Solution geöffnet wird und das .NET Framework 4.7.2 Developer Pack installiert ist. Das Repository enthält weder SDK-Style-Projekte noch `global.json` oder `PackageReference`.
-
-### Keine Anwendungen
-
-- Tool lokal auf dem BizTalk Server ausführen
-- Konto und WMI-Leserechte prüfen
-- Namespace `root\MicrosoftBizTalkServer` prüfen
-- BizTalk Administration Console auf demselben Konto testen
-
-### Einzelne Zählwerte sind 0
-
-Zuerst das Blatt `Abdeckung` prüfen. Nur bei Status `Vollständig` ist die Null durch eine erfolgreich gelesene WMI-Klasse belegt. Bei `Nicht verfügbar` oder `Begrenzt` muss die Ursache geprüft werden.
-
-Weitere technische Details stehen in [Dokumentation.md](Dokumentation.md).
+Technische Details stehen in [Dokumentation.md](Dokumentation.md).
diff --git a/deployment/run-inventory.cmd b/deployment/run-inventory.cmd
index a902161..680e99e 100644
--- a/deployment/run-inventory.cmd
+++ b/deployment/run-inventory.cmd
@@ -19,7 +19,7 @@ if "%~2"=="" (
)
echo ============================================================
-echo BEW BizTalk Application Catalog
+echo BEW BizTalk Application Catalog - Phase 1
echo Umgebung: %ENVIRONMENT%
echo Server: %COMPUTERNAME%
echo Ausgabe: %OUTPUT%
@@ -34,7 +34,7 @@ echo.
if "%EXITCODE%"=="0" (
echo Inventar erfolgreich erstellt.
) else if "%EXITCODE%"=="1" (
- echo Inventar mit Teilfehler erstellt. XLSX, Abdeckung, Findings und Log pruefen.
+ echo Inventar unvollstaendig. JSON darf nicht zusammengefuehrt werden; Log pruefen.
) else (
echo Inventar konnte nicht erstellt werden.
)
diff --git a/deployment/run-merge.cmd b/deployment/run-merge.cmd
new file mode 100644
index 0000000..5687116
--- /dev/null
+++ b/deployment/run-merge.cmd
@@ -0,0 +1,26 @@
+@echo off
+setlocal EnableExtensions
+
+set "APPDIR=%~dp0"
+set "EXE=%APPDIR%BizTalkApplicationCatalog.exe"
+
+if not exist "%EXE%" (
+ echo FEHLER: Anwendung fehlt: "%EXE%"
+ exit /b 2
+)
+if "%~1"=="" goto :usage
+if "%~2"=="" goto :usage
+
+if "%~3"=="" (
+ set "OUTPUT=%CD%\BizTalk-Anwendungskatalog\ACC-PROD"
+) else (
+ set "OUTPUT=%~3"
+)
+
+"%EXE%" --merge --acc-json "%~1" --prod-json "%~2" --output "%OUTPUT%"
+exit /b %ERRORLEVEL%
+
+:usage
+echo Aufruf:
+echo run-merge.cmd ACC-SNAPSHOT.json PROD-SNAPSHOT.json [AUSGABEORDNER]
+exit /b 2
diff --git a/scripts/package-release.cmd b/scripts/package-release.cmd
index 1281aaf..6af4efa 100644
--- a/scripts/package-release.cmd
+++ b/scripts/package-release.cmd
@@ -16,6 +16,7 @@ copy "%BIN%\BizTalkApplicationCatalog.exe" "%DEPLOY%\" >nul
copy "%BIN%\BizTalkApplicationCatalog.exe.config" "%DEPLOY%\" >nul
if exist "%BIN%\BizTalkApplicationCatalog.pdb" copy "%BIN%\BizTalkApplicationCatalog.pdb" "%DEPLOY%\" >nul
copy "%ROOT%\deployment\run-inventory.cmd" "%DEPLOY%\" >nul
+copy "%ROOT%\deployment\run-merge.cmd" "%DEPLOY%\" >nul
copy "%ROOT%\Readme.md" "%DEPLOY%\" >nul
copy "%ROOT%\Dokumentation.md" "%DEPLOY%\" >nul
diff --git a/src/BizTalkApplicationCatalog/App.config b/src/BizTalkApplicationCatalog/App.config
index 06ed7ff..d77fe51 100644
--- a/src/BizTalkApplicationCatalog/App.config
+++ b/src/BizTalkApplicationCatalog/App.config
@@ -5,6 +5,5 @@
-
diff --git a/src/BizTalkApplicationCatalog/BizTalkApplicationCatalog.csproj b/src/BizTalkApplicationCatalog/BizTalkApplicationCatalog.csproj
index 185009d..382d5ef 100644
--- a/src/BizTalkApplicationCatalog/BizTalkApplicationCatalog.csproj
+++ b/src/BizTalkApplicationCatalog/BizTalkApplicationCatalog.csproj
@@ -41,18 +41,18 @@
+
-
-
+
diff --git a/src/BizTalkApplicationCatalog/Collectors/BizTalkWmiCollector.cs b/src/BizTalkApplicationCatalog/Collectors/BizTalkWmiCollector.cs
index 1a84703..8eb5a90 100644
--- a/src/BizTalkApplicationCatalog/Collectors/BizTalkWmiCollector.cs
+++ b/src/BizTalkApplicationCatalog/Collectors/BizTalkWmiCollector.cs
@@ -3,14 +3,13 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Management;
-using System.Runtime.InteropServices;
using BizTalkApplicationCatalog.Infrastructure;
using BizTalkApplicationCatalog.Models;
namespace BizTalkApplicationCatalog.Collectors
{
///
- /// Liest die installierten Anwendungen und zugehörigen Artefakte über den lokalen BizTalk-WMI-Provider.
+ /// Liest nur die Daten, die für die Phase-1-Ansicht erforderlich sind.
///
internal sealed class BizTalkWmiCollector
{
@@ -18,282 +17,156 @@ namespace BizTalkApplicationCatalog.Collectors
private readonly ConsoleFileLogger logger;
private readonly ManagementScope scope;
private readonly TimeSpan timeout;
- private readonly int maxRowsPerType;
private readonly Dictionary receivePortApplications =
new Dictionary(StringComparer.OrdinalIgnoreCase);
public BizTalkWmiCollector(
InventoryDocument document,
ConsoleFileLogger logger,
- int timeoutSeconds,
- int maxRowsPerType)
+ int timeoutSeconds)
{
this.document = document;
this.logger = logger;
timeout = TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds));
- this.maxRowsPerType = Math.Max(100, maxRowsPerType);
scope = new ManagementScope(
@"\\" + Environment.MachineName + @"\root\MicrosoftBizTalkServer");
scope.Options.Timeout = timeout;
}
- ///
- /// Stellt zuerst die vollständige Primärliste her und ergänzt anschließend optionale Details.
- ///
public void Collect()
{
scope.Connect();
CollectApplications();
-
- // Receive Ports werden vor Receive Locations gelesen, damit deren Anwendung
- // auch dann aufgelöst werden kann, wenn die Location sie nicht direkt liefert.
- foreach (var descriptor in ArtifactDescriptors())
- {
- CollectOptionalArtifacts(descriptor);
- }
-
- CollectOptionalHosts("MSBTS_HostSetting", "Host");
- CollectOptionalHosts("MSBTS_HostInstance", "Hostinstanz");
- CollectOptionalHosts("MSBTS_ReceiveHandler", "Receive Handler");
- if (!CollectOptionalHosts("MSBTS_SendHandler2", "Send Handler"))
- {
- CollectOptionalHosts("MSBTS_SendHandler", "Send Handler");
- }
+ CollectReceivePortMappings();
+ CollectSendPortEndpoints();
+ CollectReceiveLocationEndpoints();
document.Applications.Sort((left, right) =>
string.Compare(left.Name, right.Name, StringComparison.OrdinalIgnoreCase));
- document.Artifacts.Sort(CompareArtifacts);
- document.Hosts.Sort((left, right) =>
+ document.Endpoints.Sort((left, right) =>
{
- var category = string.Compare(left.Category, right.Category, StringComparison.OrdinalIgnoreCase);
- return category != 0
- ? category
- : string.Compare(left.Name, right.Name, StringComparison.OrdinalIgnoreCase);
+ var application = string.Compare(
+ left.ApplicationName,
+ right.ApplicationName,
+ StringComparison.OrdinalIgnoreCase);
+ return application != 0
+ ? application
+ : string.Compare(
+ left.AdapterType,
+ right.AdapterType,
+ StringComparison.OrdinalIgnoreCase);
});
}
private void CollectApplications()
{
- var count = 0;
foreach (var row in Query("SELECT * FROM MSBTS_Application"))
{
using (row)
{
var name = First(row, "Name", "ApplicationName");
- if (string.IsNullOrWhiteSpace(name)) continue;
- document.Applications.Add(new ApplicationRecord
+ if (!string.IsNullOrWhiteSpace(name))
{
- Name = name,
- Description = First(row, "Description"),
- Status = FormatStatus(First(row, "Status")),
- IsDefault = FormatBoolean(First(row, "IsDefault")),
- Source = "MSBTS_Application"
- });
+ document.Applications.Add(new ApplicationRecord { Name = name.Trim() });
+ }
+ }
+ }
+
+ if (document.Applications.Count == 0)
+ {
+ throw new InvalidOperationException(
+ "MSBTS_Application lieferte keine Anwendungen.");
+ }
+
+ logger.Info(document.Applications.Count
+ + " BizTalk-Anwendung(en) gefunden.");
+ }
+
+ private void CollectReceivePortMappings()
+ {
+ var count = 0;
+ foreach (var row in Query("SELECT * FROM MSBTS_ReceivePort"))
+ {
+ using (row)
+ {
+ var name = First(row, "Name", "ReceivePortName");
+ var application = First(row, "ApplicationName", "Application");
+ if (string.IsNullOrWhiteSpace(name)) continue;
+ receivePortApplications[name] = application;
count++;
}
}
+ logger.Info(count + " Receive-Port-Zuordnung(en) gelesen.");
+ }
- document.Coverage.Add(new CoverageRecord
+ private void CollectSendPortEndpoints()
+ {
+ var count = 0;
+ foreach (var row in Query("SELECT * FROM MSBTS_SendPort"))
{
- DataSource = "MSBTS_Application",
- Status = count > 0 ? "Vollständig" : "Fehler",
- RowCount = count,
- Required = "Ja",
- Message = count > 0
- ? "Primärquelle der vollständigen Anwendungsliste."
- : "Keine Anwendung geliefert."
- });
- if (count == 0)
+ using (row)
+ {
+ var application = First(row, "ApplicationName", "Application");
+ AddEndpoint(application, First(
+ row,
+ "PTTransportType",
+ "PrimaryTransportType",
+ "AdapterName",
+ "TransportType"));
+ count++;
+
+ var secondaryAdapter = First(
+ row,
+ "STTransportType",
+ "SecondaryTransportType");
+ if (!string.IsNullOrWhiteSpace(secondaryAdapter))
+ {
+ AddEndpoint(application, secondaryAdapter);
+ count++;
+ }
+ }
+ }
+ logger.Info(count + " Send-Endpunkt(e) gefunden.");
+ }
+
+ private void CollectReceiveLocationEndpoints()
+ {
+ var count = 0;
+ foreach (var row in Query("SELECT * FROM MSBTS_ReceiveLocation"))
+ {
+ using (row)
+ {
+ var application = First(row, "ApplicationName", "Application");
+ if (string.IsNullOrWhiteSpace(application))
+ {
+ var receivePort = First(row, "ReceivePortName");
+ receivePortApplications.TryGetValue(receivePort, out application);
+ }
+
+ AddEndpoint(
+ application,
+ First(row, "AdapterName", "TransportType", "PTTransportType"));
+ count++;
+ }
+ }
+ logger.Info(count + " Receive-Endpunkt(e) gefunden.");
+ }
+
+ private void AddEndpoint(string applicationName, string adapterType)
+ {
+ if (string.IsNullOrWhiteSpace(applicationName))
{
throw new InvalidOperationException(
- "MSBTS_Application lieferte keine Anwendungen. Zielserver und Berechtigung prüfen.");
+ "Ein Endpunkt konnte keiner BizTalk-Anwendung zugeordnet werden.");
}
- logger.Info(count + " installierte BizTalk-Anwendung(en) gefunden.");
- }
-
- private void CollectOptionalArtifacts(ArtifactDescriptor descriptor)
- {
- try
+ document.Endpoints.Add(new EndpointRecord
{
- var count = 0;
- var truncated = false;
- foreach (var row in Query("SELECT * FROM " + descriptor.ClassName))
- {
- using (row)
- {
- if (count >= maxRowsPerType)
- {
- truncated = true;
- break;
- }
-
- var record = CreateArtifact(row, descriptor.DisplayName);
- if (string.IsNullOrWhiteSpace(record.Name)) continue;
- if (record.Type == "Receive Port")
- {
- receivePortApplications[record.Name] = record.ApplicationName;
- }
- if (record.Type == "Receive Location"
- && string.IsNullOrWhiteSpace(record.ApplicationName)
- && receivePortApplications.ContainsKey(record.ParentName))
- {
- record.ApplicationName = receivePortApplications[record.ParentName];
- }
- document.Artifacts.Add(record);
- count++;
- }
- }
-
- document.Coverage.Add(new CoverageRecord
- {
- DataSource = descriptor.ClassName,
- Status = truncated ? "Begrenzt" : "Vollständig",
- RowCount = count,
- Required = "Nein",
- Message = truncated
- ? "Detailzeilen auf " + maxRowsPerType + " begrenzt."
- : "WMI-Klasse erfolgreich gelesen."
- });
- logger.Info(descriptor.DisplayName + ": " + count + " Datensatz/Datensätze.");
- if (truncated)
- {
- AddFinding(
- "Warnung",
- descriptor.DisplayName,
- "Detailzeilen wurden bei " + maxRowsPerType + " Einträgen begrenzt.",
- "MaxRowsPerArtifactType kontrolliert erhöhen und Inventar erneut ausführen.");
- }
- }
- catch (Exception exception) when (IsRecoverableWmiException(exception))
- {
- document.Coverage.Add(new CoverageRecord
- {
- DataSource = descriptor.ClassName,
- Status = "Nicht verfügbar",
- RowCount = 0,
- Required = "Nein",
- Message = exception.Message
- });
- AddFinding(
- "Hinweis",
- descriptor.DisplayName,
- "Optionale WMI-Klasse konnte nicht gelesen werden: " + exception.Message,
- "Berechtigung und Verfügbarkeit der WMI-Klasse prüfen; Wert 0 nicht als fachlich bestätigt werten.");
- logger.Warning(descriptor.ClassName + " nicht verfügbar: " + exception.Message);
- }
- }
-
- private bool CollectOptionalHosts(string className, string category)
- {
- try
- {
- var count = 0;
- foreach (var row in Query("SELECT * FROM " + className))
- {
- using (row)
- {
- var name = First(row, "Name", "HostName", "AdapterName", "RunningServer");
- if (string.IsNullOrWhiteSpace(name)) continue;
- document.Hosts.Add(new HostRecord
- {
- Category = category,
- Name = name,
- Server = First(row, "RunningServer", "ServerName"),
- Status = FormatStatus(First(row, "ServiceState", "Status")),
- Type = First(row, "HostType"),
- WindowsGroup = First(row, "NTGroupName"),
- Is32BitOnly = FormatBoolean(First(row, "IsHost32BitOnly")),
- Trusted = FormatBoolean(First(row, "AuthTrusted")),
- AdapterName = First(row, "AdapterName")
- });
- count++;
- }
- }
- document.Coverage.Add(new CoverageRecord
- {
- DataSource = className,
- Status = "Vollständig",
- RowCount = count,
- Required = "Nein",
- Message = "WMI-Klasse erfolgreich gelesen."
- });
- logger.Info(category + ": " + count + " Datensatz/Datensätze.");
- return true;
- }
- catch (Exception exception) when (IsRecoverableWmiException(exception))
- {
- document.Coverage.Add(new CoverageRecord
- {
- DataSource = className,
- Status = "Nicht verfügbar",
- RowCount = 0,
- Required = "Nein",
- Message = exception.Message
- });
- logger.Warning(className + " nicht verfügbar: " + exception.Message);
- return false;
- }
- }
-
- private ArtifactRecord CreateArtifact(ManagementBaseObject row, string type)
- {
- var record = new ArtifactRecord
- {
- Type = type,
- ApplicationName = First(row, "ApplicationName", "Application"),
- Name = First(
- row,
- "Name",
- "AssemblyName",
- "FullName",
- "ReceivePortName",
- "OrchestrationName"),
- Status = FormatStatus(First(row, "Status", "ServiceStatus", "IsDisabled")),
- HostName = First(row, "HostName", "SendHandler", "ReceiveHandler"),
- AdapterName = First(
- row,
- "PTTransportType",
- "AdapterName",
- "TransportType"),
- ParentName = First(row, "ReceivePortName", "SendPortGroupName"),
- Address = SensitiveDataSanitizer.Sanitize(First(
- row,
- "PTAddress",
- "InboundTransportURL",
- "Address"))
- };
-
- AddProperty(row, record, "Description");
- AddProperty(row, record, "IsTwoWay");
- AddProperty(row, record, "IsDynamic");
- AddProperty(row, record, "IsDisabled");
- AddProperty(row, record, "ReceivePipeline");
- AddProperty(row, record, "SendPipeline");
- AddProperty(row, record, "STTransportType");
- AddProperty(row, record, "STAddress");
- AddProperty(row, record, "AssemblyName");
- AddProperty(row, record, "FullName");
- AddProperty(row, record, "TargetNameSpace");
- AddProperty(row, record, "RootName");
- AddProperty(row, record, "Tracking");
- return record;
- }
-
- private static IEnumerable ArtifactDescriptors()
- {
- return new[]
- {
- new ArtifactDescriptor("MSBTS_Orchestration", "Orchestrierung"),
- new ArtifactDescriptor("MSBTS_SendPort", "Send Port"),
- new ArtifactDescriptor("MSBTS_SendPortGroup", "Send Port Group"),
- new ArtifactDescriptor("MSBTS_ReceivePort", "Receive Port"),
- new ArtifactDescriptor("MSBTS_ReceiveLocation", "Receive Location"),
- new ArtifactDescriptor("MSBTS_Assembly", "Assembly"),
- new ArtifactDescriptor("MSBTS_Schema", "Schema"),
- new ArtifactDescriptor("MSBTS_Map", "Map"),
- new ArtifactDescriptor("MSBTS_Pipeline", "Pipeline")
- };
+ ApplicationName = applicationName.Trim(),
+ AdapterType = string.IsNullOrWhiteSpace(adapterType)
+ ? "Unbekannt"
+ : adapterType.Trim()
+ });
}
private List Query(string query)
@@ -304,38 +177,15 @@ namespace BizTalkApplicationCatalog.Collectors
Rewindable = false,
Timeout = timeout
};
- using (var searcher = new ManagementObjectSearcher(scope, new ObjectQuery(query), options))
+ using (var searcher = new ManagementObjectSearcher(
+ scope,
+ new ObjectQuery(query),
+ options))
{
return searcher.Get().Cast().ToList();
}
}
- private void AddFinding(string severity, string area, string message, string action)
- {
- document.Findings.Add(new Finding
- {
- Severity = severity,
- Area = area,
- Message = message,
- RecommendedAction = action
- });
- }
-
- private static void AddProperty(
- ManagementBaseObject row,
- ArtifactRecord target,
- string propertyName)
- {
- var value = First(row, propertyName);
- if (!string.IsNullOrWhiteSpace(value))
- {
- target.Properties.Add(new NameValueRecord(
- propertyName,
- SensitiveDataSanitizer.RedactProperty(propertyName, value),
- "WMI"));
- }
- }
-
private static string First(ManagementBaseObject row, params string[] names)
{
foreach (var name in names)
@@ -344,78 +194,15 @@ namespace BizTalkApplicationCatalog.Collectors
{
var value = row[name];
if (value == null) continue;
- var text = ConvertValue(value);
+ var text = Convert.ToString(value, CultureInfo.InvariantCulture);
if (!string.IsNullOrWhiteSpace(text)) return text;
}
- catch (Exception exception) when (IsRecoverableWmiException(exception))
+ catch (ManagementException)
{
- // Die Eigenschaft ist in dieser BizTalk-Version/Klasse nicht vorhanden.
+ // WMI-Properties unterscheiden sich zwischen Providerständen.
}
}
return string.Empty;
}
-
- private static string ConvertValue(object value)
- {
- var array = value as Array;
- if (array != null && !(value is byte[]))
- {
- return string.Join(", ", array.Cast