diff --git a/src/BizTalkStatusTool.ps1 b/src/BizTalkStatusTool.ps1
index 123876e..388aec2 100644
--- a/src/BizTalkStatusTool.ps1
+++ b/src/BizTalkStatusTool.ps1
@@ -1,278 +1,676 @@
-<#!
-BizTalk Status Tool (PowerShell only, Remote Server Support)
-Compatible with:
-- Windows Server 2019
-- PowerShell 5.1
-- BizTalk Server 2020 (WMI under root\MicrosoftBizTalkServer)
-Author: Copilot
-Version: 1.3.0
+<#
+BizTalk Status Tool – Extended Version
+Includes:
+- Applications Snapshot (RL/SP/ORCH)
+- Host Instances Snapshot
+- JSON / CSV / HTML / Console
+- Compare (Before / After)
+- HostInstance Diff (New / Removed / Changed)
#>
-$Global:LogFile = Join-Path (Get-Location) "BizTalkStatusTool.log"
-
-function Write-Log {
- param(
- [string]$Message,
- [ValidateSet('INFO','WARN','ERROR','DEBUG')]
- [string]$Level = 'INFO'
- )
- $timestamp = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
- $line = "[$timestamp][$Level] $Message"
- Write-Host $line
- Add-Content -Path $Global:LogFile -Value $line
-}
-
-# ----------------- Helpers: Status mapping & coloring -----------------
-function Format-Status {
- param(
- [Parameter(Mandatory=$true)][string]$ArtifactType,
- [Parameter(Mandatory=$false)]$Value
- )
- $result = [ordered]@{ Text=''; Class='neutral'; ConsoleColor='Yellow' }
-
- switch ($ArtifactType) {
- 'ReceiveLocation' {
- # Value is boolean (Enabled)
- $enabled = [bool]$Value
- if ($enabled) { $result.Text='Enabled'; $result.Class='ok'; $result.ConsoleColor='Green' }
- else { $result.Text='Disabled'; $result.Class='bad'; $result.ConsoleColor='Red' }
- }
- 'SendPort' {
- # MSBTS_SendPort.Status: 1=Bound, 2=Stopped, 3=Started
- $code = [int]$Value
- switch ($code) {
- 3 { $result.Text='Started'; $result.Class='ok'; $result.ConsoleColor='Green' }
- 2 { $result.Text='Stopped'; $result.Class='bad'; $result.ConsoleColor='Red' }
- 1 { $result.Text='Bound'; $result.Class='bad'; $result.ConsoleColor='Red' }
- default { $result.Text="Unknown($code)"; $result.Class='bad'; $result.ConsoleColor='Red' }
- }
- }
- 'Orchestration' {
- # MSBTS_Orchestration.OrchestrationStatus: 1=Unbound, 2=Bound, 3=Stopped, 4=Started
- $code = [int]$Value
- switch ($code) {
- 4 { $result.Text='Started'; $result.Class='ok'; $result.ConsoleColor='Green' }
- 3 { $result.Text='Stopped'; $result.Class='bad'; $result.ConsoleColor='Red' }
- 2 { $result.Text='Bound'; $result.Class='bad'; $result.ConsoleColor='Red' }
- 1 { $result.Text='Unbound'; $result.Class='bad'; $result.ConsoleColor='Red' }
- default { $result.Text="Unknown($code)"; $result.Class='bad'; $result.ConsoleColor='Red' }
- }
- }
- default {
- $result.Text = [string]$Value
- }
- }
- return [pscustomobject]$result
-}
-
-function Write-ColoredKV {
- param(
- [string]$Key,
- [psobject]$Formatted
- )
- Write-Host ("{0,-15}" -f ($Key + ':')) -NoNewline
- Write-Host $Formatted.Text -ForegroundColor $Formatted.ConsoleColor
-}
-
-# ----------------- Snapshot -----------------
-function Get-BizTalkSnapshot {
- param(
- [string]$OutputFile = 'snapshot.json',
- [string]$Server = $env:COMPUTERNAME
- )
- Write-Log "Erzeuge Snapshot von Server '$Server' → Datei: $OutputFile"
- try {
- $apps = Get-WmiObject MSBTS_Application -Namespace "root\MicrosoftBizTalkServer" -ComputerName $Server -ErrorAction Stop
- } catch {
- Write-Log "FEHLER: Verbindung zu BizTalk-WMI auf '$Server' fehlgeschlagen: $($_.Exception.Message)" 'ERROR'
- throw
- }
-
- $snapshot = @()
- foreach ($app in $apps) {
- $appName = $app.Name
- Write-Log "Lese Anwendung '$appName'"
-
- $rl = Get-WmiObject MSBTS_ReceiveLocation -Namespace root\MicrosoftBizTalkServer -ComputerName $Server |
- Where-Object { $_.ApplicationName -eq $appName } |
- Select-Object Name,
- @{n='Enabled'; e={ -not $_.IsDisabled }},
- AdapterName,
- @{n='Address'; e={$_.InboundTransportURL}}
-
- $sp = Get-WmiObject MSBTS_SendPort -Namespace root\MicrosoftBizTalkServer -ComputerName $Server |
- Where-Object { $_.ApplicationName -eq $appName } |
- Select-Object Name,
- @{n='Status';e={$_.Status}},
- @{n='PrimaryTransportType';e={$_.PTTransportType}},
- @{n='PrimaryTransportAddress';e={$_.PTAddress}}
-
- $orch = Get-WmiObject MSBTS_Orchestration -Namespace root\MicrosoftBizTalkServer -ComputerName $Server |
- Where-Object { $_.ApplicationName -eq $appName } |
- Select-Object Name, @{n='OrchestrationStatus';e={$_.OrchestrationStatus}}
-
- $snapshot += [PSCustomObject]@{
- Application = $appName
- ReceiveLocations = $rl
- SendPorts = $sp
- Orchestrations = $orch
- }
- }
-
- $snapshot | ConvertTo-Json -Depth 8 | Out-File $OutputFile -Encoding UTF8
- Write-Log "Snapshot gespeichert: $OutputFile"
-}
-
-# ----------------- Diff + HTML + Console Output -----------------
-function Compare-BizTalkSnapshots {
- param(
- [Parameter(Mandatory=$true)][string]$Before,
- [Parameter(Mandatory=$true)][string]$After,
- [string]$HtmlReport = 'BizTalkDiff.html'
- )
- Write-Log "Vergleiche Snapshots: $Before ↔ $After"
-
- $snapBefore = Get-Content $Before | ConvertFrom-Json
- $snapAfter = Get-Content $After | ConvertFrom-Json
-
- $differences = @()
-
- # Helper: add diff row
- function Add-Diff {
- param($appName,$type,$name,$beforeVal,$afterVal)
- $b = Format-Status -ArtifactType $type -Value $beforeVal
- $a = Format-Status -ArtifactType $type -Value $afterVal
- $differences += [PSCustomObject]@{
- Application = $appName
- ArtifactType = $type
- Name = $name
- Before = $beforeVal
- After = $afterVal
- BeforeText = $b.Text
- BeforeClass = $b.Class
- AfterText = $a.Text
- AfterClass = $a.Class
- }
- }
-
- foreach ($appAfter in $snapAfter) {
- $appBefore = $snapBefore | Where-Object { $_.Application -eq $appAfter.Application }
-
- # Receive Locations
- foreach ($rlAfter in $appAfter.ReceiveLocations) {
- $rlBefore = $appBefore.ReceiveLocations | Where-Object { $_.Name -eq $rlAfter.Name }
- if ($null -eq $rlBefore) { Add-Diff $appAfter.Application 'ReceiveLocation' $rlAfter.Name $null $rlAfter.Enabled; continue }
- if ($rlBefore.Enabled -ne $rlAfter.Enabled) { Add-Diff $appAfter.Application 'ReceiveLocation' $rlAfter.Name $rlBefore.Enabled $rlAfter.Enabled }
- }
- # Detect removed RL
- foreach ($rlBefore in $appBefore.ReceiveLocations) {
- $rlAfter = $appAfter.ReceiveLocations | Where-Object { $_.Name -eq $rlBefore.Name }
- if ($null -eq $rlAfter) { Add-Diff $appAfter.Application 'ReceiveLocation' $rlBefore.Name $rlBefore.Enabled $null }
- }
-
- # Send Ports
- foreach ($spAfter in $appAfter.SendPorts) {
- $spBefore = $appBefore.SendPorts | Where-Object { $_.Name -eq $spAfter.Name }
- if ($null -eq $spBefore) { Add-Diff $appAfter.Application 'SendPort' $spAfter.Name $null $spAfter.Status; continue }
- if ($spBefore.Status -ne $spAfter.Status) { Add-Diff $appAfter.Application 'SendPort' $spAfter.Name $spBefore.Status $spAfter.Status }
- }
- foreach ($spBefore in $appBefore.SendPorts) {
- $spAfter = $appAfter.SendPorts | Where-Object { $_.Name -eq $spBefore.Name }
- if ($null -eq $spAfter) { Add-Diff $appAfter.Application 'SendPort' $spBefore.Name $spBefore.Status $null }
- }
-
- # Orchestrations
- foreach ($oAfter in $appAfter.Orchestrations) {
- $oBefore = $appBefore.Orchestrations | Where-Object { $_.Name -eq $oAfter.Name }
- if ($null -eq $oBefore) { Add-Diff $appAfter.Application 'Orchestration' $oAfter.Name $null $oAfter.OrchestrationStatus; continue }
- if ($oBefore.OrchestrationStatus -ne $oAfter.OrchestrationStatus) { Add-Diff $appAfter.Application 'Orchestration' $oAfter.Name $oBefore.OrchestrationStatus $oAfter.OrchestrationStatus }
- }
- foreach ($oBefore in $appBefore.Orchestrations) {
- $oAfter = $appAfter.Orchestrations | Where-Object { $_.Name -eq $oBefore.Name }
- if ($null -eq $oAfter) { Add-Diff $appAfter.Application 'Orchestration' $oBefore.Name $oBefore.OrchestrationStatus $null }
- }
- }
-
- # ---------------- Console text summary with colors ----------------
- Write-Host ""; Write-Host "------------------------------------------------------------" -ForegroundColor Yellow
- Write-Host " TEXTUELLE ÄNDERUNGSÜBERSICHT (StdOut)" -ForegroundColor Yellow
- Write-Host "------------------------------------------------------------" -ForegroundColor Yellow
-
- if ($differences.Count -eq 0) {
- Write-Host "Keine Unterschiede gefunden." -ForegroundColor Green
- } else {
- foreach ($d in $differences) {
- Write-Host ""; Write-Host ("Application: {0}" -f $d.Application) -ForegroundColor Cyan
- Write-Host ("Artifact: {0}" -f $d.ArtifactType)
- Write-Host ("Name: {0}" -f $d.Name)
- Write-ColoredKV -Key 'Before' -Formatted ([pscustomobject]@{ Text=$d.BeforeText; ConsoleColor=($(if($d.BeforeClass -eq 'ok'){'Green'}elseif($d.BeforeClass -eq 'bad'){'Red'}else{'Yellow'})) })
- Write-ColoredKV -Key 'After' -Formatted ([pscustomobject]@{ Text=$d.AfterText; ConsoleColor=($(if($d.AfterClass -eq 'ok'){'Green'}elseif($d.AfterClass -eq 'bad'){'Red'}else{'Yellow'})) })
- }
- }
-
- # ---------------- HTML report ----------------
- Write-Log "Erzeuge HTML-Report: $HtmlReport"
-
- $htmlHeader = @"
-
-
-BizTalk Differences Report
-
-
-
-BizTalk Differences Report
-Vergleich: $Before → $After
-
-
-| Application |
-Artifact |
-Name |
-Before |
-After |
-
-"@
-
- $rows = foreach ($d in $differences) {
- "| $($d.Application) | $($d.ArtifactType) | $($d.Name) | $($d.BeforeText) | $($d.AfterText) |
"
- }
-
- $htmlFooter = "
"
-
- ($htmlHeader + ($rows -join "`n") + $htmlFooter) | Out-File $HtmlReport -Encoding UTF8
-
- Write-Host ""; Write-Host ("HTML-Report erstellt: {0}" -f $HtmlReport) -ForegroundColor Green
- Write-Host "→ Im selben Verzeichnis öffnen für die farbige Übersicht." -ForegroundColor DarkYellow
-
- return $differences
-}
-
-# ---------------- Parameters (CLI) ----------------
+# ======================================================
+# PARAMETERS
+# ======================================================
param(
[switch]$Before,
[switch]$After,
[switch]$Compare,
- [string]$Server = $env:COMPUTERNAME,
- [string]$OutDir = '.'
+ [switch]$Diag,
+ [string]$Server,
+ [string]$MgmtDbServer,
+ [string]$MgmtDbName,
+ [string]$OutDir
)
-if ($PSBoundParameters.ContainsKey('OutDir')) { New-Item -ItemType Directory -Force -Path $OutDir | Out-Null; Set-Location $OutDir }
+if (-not $Server) { $Server = $env:COMPUTERNAME }
+if (-not $OutDir) { $OutDir = "." }
-if ($Before) { Get-BizTalkSnapshot -OutputFile 'before.json' -Server $Server; exit }
-elif ($After) { Get-BizTalkSnapshot -OutputFile 'after.json' -Server $Server; exit }
-elif ($Compare) { Compare-BizTalkSnapshots -Before 'before.json' -After 'after.json' -HtmlReport 'BizTalkDiff.html'; exit }
-else {
- Write-Host "Verwendung:" -ForegroundColor Yellow
- Write-Host " Snapshot vor Downtime: .\BizTalkStatusTool.ps1 -Before -Server -OutDir "
- Write-Host " Snapshot nach Downtime: .\BizTalkStatusTool.ps1 -After -Server -OutDir "
- Write-Host " Diff + HTML Report: .\BizTalkStatusTool.ps1 -Compare"
+$ErrorActionPreference = "Stop"
+$Global:LogFile = Join-Path (Get-Location) "BizTalkStatusTool.log"
+
+# ======================================================
+# LOG
+# ======================================================
+function Write-Log {
+ param([string]$Message,[ValidateSet('INFO','WARN','ERROR','DEBUG')]$Level='INFO')
+
+ $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
+ $line = "[$ts][$Level] $Message"
+ $fg = switch ($Level) {
+ INFO {"Gray"} WARN {"Yellow"} ERROR {"Red"} DEBUG {"DarkCyan"}
+ }
+ Write-Host $line -ForegroundColor $fg
+ Add-Content -Path $Global:LogFile -Value $line
}
+
+# ======================================================
+# STATUS MAPPING
+# ======================================================
+function Format-Status {
+ param([string]$ArtifactType, $Value)
+
+ $r = [ordered]@{
+ Text = ""
+ Class = "neutral"
+ ConsoleColor = "Yellow"
+ }
+
+ switch ($ArtifactType) {
+
+ "ReceiveLocation" {
+ if ($Value -eq $true) {
+ $r.Text="Enabled"; $r.Class="ok"; $r.ConsoleColor="Green"
+ }
+ elseif ($Value -eq $false) {
+ $r.Text="Disabled"; $r.Class="bad"; $r.ConsoleColor="Red"
+ }
+ }
+
+ "SendPort" {
+ switch ([int]$Value) {
+ 3 { $r.Text="Started"; $r.Class="ok"; $r.ConsoleColor="Green" }
+ 2 { $r.Text="Stopped"; $r.Class="bad"; $r.ConsoleColor="Red" }
+ 1 { $r.Text="Bound"; $r.Class="bad"; $r.ConsoleColor="Red" }
+ default { $r.Text="Unknown"; $r.Class="bad"; $r.ConsoleColor="Red" }
+ }
+ }
+
+ "Orchestration" {
+ switch ([int]$Value) {
+ 4 { $r.Text="Started"; $r.Class="ok"; $r.ConsoleColor="Green" }
+ 3 { $r.Text="Stopped"; $r.Class="bad"; $r.ConsoleColor="Red" }
+ 2 { $r.Text="Bound"; $r.Class="bad"; $r.ConsoleColor="Red" }
+ default { $r.Text="Unknown"; $r.Class="bad"; $r.ConsoleColor="Red" }
+ }
+ }
+
+ "HostInstance" {
+ switch ([int]$Value) {
+ 4 { $r.Text="Started"; $r.Class="ok"; $r.ConsoleColor="Green" }
+ 2 { $r.Text="StartPending"; $r.Class="warn"; $r.ConsoleColor="Yellow" }
+ 3 { $r.Text="StopPending"; $r.Class="warn"; $r.ConsoleColor="Yellow" }
+ 1 { $r.Text="Stopped"; $r.Class="bad"; $r.ConsoleColor="Red" }
+ default { $r.Text="Unknown"; $r.Class="bad"; $r.ConsoleColor="Red" }
+ }
+ }
+ }
+
+ return [pscustomobject]$r
+}
+
+# ======================================================
+# MGMT DB
+# ======================================================
+function Get-BizTalkMgmtDbInfo {
+ param([string]$MgmtDbServer,[string]$MgmtDbName)
+
+ $reg = "HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0\Administration"
+
+ try {
+ $p = Get-ItemProperty $reg
+ if (-not $MgmtDbServer) { $MgmtDbServer = $p.MgmtDBServer }
+ if (-not $MgmtDbName) { $MgmtDbName = $p.MgmtDBName }
+ }
+ catch {
+ if (-not $MgmtDbServer) { $MgmtDbServer = "localhost" }
+ if (-not $MgmtDbName) { $MgmtDbName = "BizTalkMgmtDb" }
+ }
+
+ return @{ Server=$MgmtDbServer; Name=$MgmtDbName }
+}
+
+# ======================================================
+# HOST INSTANCES
+# ======================================================
+function Get-BizTalkHostInstances {
+ param([string]$Server)
+
+ $wmi = @{
+ Namespace = "root\MicrosoftBizTalkServer"
+ ComputerName = $Server
+ ErrorAction = 'Stop'
+ }
+
+ $list = Get-WmiObject MSBTS_HostInstance @wmi
+
+ $result = foreach ($hi in $list) {
+ $st = Format-Status -ArtifactType "HostInstance" -Value $hi.ServiceState
+ [pscustomobject]@{
+ InstanceName = $hi.InstanceName
+ HostName = $hi.HostName
+ Server = $hi.RunningServer
+ RawState = $hi.ServiceState
+ StateText = $st.Text
+ StateClass = $st.Class
+ ConsoleColor = $st.ConsoleColor
+ }
+ }
+
+ return $result
+}
+
+function Show-HostInstancesConsole {
+ param($HostInstances)
+ Write-Host "`n=== Host Instances ===" -ForegroundColor Yellow
+ foreach ($hi in $HostInstances) {
+ Write-Host ("{0,-35} {1,-20} {2,-10}" -f $hi.InstanceName,$hi.HostName,$hi.StateText) `
+ -ForegroundColor $hi.ConsoleColor
+ }
+}
+
+function Export-HostInstancesHtml {
+ param($HostInstances)
+
+ $html = @()
+ $html += "Host Instances
"
+ $html += ""
+ $html += "| Instance | Host | Server | Status |
"
+
+ foreach ($hi in $HostInstances) {
+ $html += "
+ | $($hi.InstanceName) |
+ $($hi.HostName) |
+ $($hi.Server) |
+ $($hi.StateText) |
+
"
+ }
+
+ $html += "
"
+ return ($html -join "`n")
+}
+
+function Export-HostInstancesCsv {
+ param($HostInstances, [string]$CsvFile)
+ $HostInstances |
+ Select InstanceName,HostName,Server,StateText |
+ Export-Csv -NoTypeInformation -Encoding UTF8 -Path $CsvFile
+}
+
+# ======================================================
+# SNAPSHOT
+# ======================================================
+function Get-BizTalkSnapshot {
+ param(
+ [string]$OutputFile,
+ [string]$Server,
+ [string]$MgmtDbServer,
+ [string]$MgmtDbName
+ )
+
+ Write-Log "Snapshot: Server=$Server File=$OutputFile"
+
+ [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.BizTalk.ExplorerOM")
+ $db = Get-BizTalkMgmtDbInfo -MgmtDbServer $MgmtDbServer -MgmtDbName $MgmtDbName
+
+ $cat = New-Object Microsoft.BizTalk.ExplorerOM.BtsCatalogExplorer
+ $cat.ConnectionString = "Server={0};Database={1};Integrated Security=SSPI" -f $db.Server,$db.Name
+
+ $apps = $cat.Applications
+
+ # WMI lookup tables
+ $wmi = @{ Namespace='root\MicrosoftBizTalkServer'; ComputerName=$Server; ErrorAction='Stop' }
+
+ $rlW = Get-WmiObject MSBTS_ReceiveLocation @wmi |
+ Select Name, @{n='Enabled';e={-not $_.IsDisabled}}, AdapterName, @{n='Address';e={$_.InboundTransportURL}}
+
+ $spW = Get-WmiObject MSBTS_SendPort @wmi |
+ Select Name, @{n='Status';e={$_.Status}}, @{n='PrimaryTransportType';e={$_.PTTransportType}},
+ @{n='PrimaryTransportAddress';e={$_.PTAddress}}
+
+ $orW = Get-WmiObject MSBTS_Orchestration @wmi |
+ Select Name, @{n='OrchestrationStatus';e={$_.OrchestrationStatus}}
+
+ $mapRL=@{}; foreach($i in $rlW){$mapRL[$i.Name]=$i}
+ $mapSP=@{}; foreach($i in $spW){$mapSP[$i.Name]=$i}
+ $mapOR=@{}; foreach($i in $orW){$mapOR[$i.Name]=$i}
+
+ $snapshot=@()
+
+ foreach ($app in $apps) {
+
+ $rlItems=@()
+ foreach ($rp in $app.ReceivePorts) {
+ foreach ($rl in $rp.ReceiveLocations) {
+ if ($mapRL.ContainsKey($rl.Name)) {
+ $w = $mapRL[$rl.Name]
+ $rlItems += [pscustomobject]@{
+ Name=$rl.Name
+ Enabled=$w.Enabled
+ AdapterName=$w.AdapterName
+ Address=$w.Address
+ }
+ }
+ }
+ }
+
+ $spItems=@()
+ foreach ($sp in $app.SendPorts) {
+ if ($mapSP.ContainsKey($sp.Name)) {
+ $w = $mapSP[$sp.Name]
+ $spItems += [pscustomobject]@{
+ Name=$sp.Name
+ Status=$w.Status
+ PrimaryTransportType=$w.PrimaryTransportType
+ PrimaryTransportAddress=$w.PrimaryTransportAddress
+ }
+ }
+ }
+
+ $orItems=@()
+ foreach ($o in $app.Orchestrations) {
+ $key = if ($mapOR.ContainsKey($o.FullName)) { $o.FullName } else { $o.Name }
+ if ($mapOR.ContainsKey($key)) {
+ $w = $mapOR[$key]
+ $orItems += [pscustomobject]@{
+ Name=$o.FullName
+ OrchestrationStatus=$w.OrchestrationStatus
+ }
+ }
+ }
+
+ $snapshot += [pscustomobject]@{
+ Application=$app.Name
+ ReceiveLocations=$rlItems
+ SendPorts=$spItems
+ Orchestrations=$orItems
+ }
+ }
+
+ # Host Instances
+ $hostInstances = Get-BizTalkHostInstances -Server $Server
+
+ # Export JSON (Applications + HostInstances)
+ $full = [pscustomobject]@{
+ Applications = $snapshot
+ HostInstances = $hostInstances
+ }
+
+ $full | ConvertTo-Json -Depth 8 | Out-File $OutputFile -Encoding UTF8
+
+ # Export CSV
+ $csvArtifact = foreach ($app in $snapshot) {
+ foreach ($rl in $app.ReceiveLocations) {
+ $st = Format-Status -ArtifactType "ReceiveLocation" -Value $rl.Enabled
+ [pscustomobject]@{
+ Application=$app.Application
+ Type="ReceiveLocation"
+ Name=$rl.Name
+ Status=$st.Text
+ }
+ }
+ foreach ($sp in $app.SendPorts) {
+ $st = Format-Status -ArtifactType "SendPort" -Value $sp.Status
+ [pscustomobject]@{
+ Application=$app.Application
+ Type="SendPort"
+ Name=$sp.Name
+ Status=$st.Text
+ }
+ }
+ foreach ($o in $app.Orchestrations) {
+ $st = Format-Status -ArtifactType "Orchestration" -Value $o.OrchestrationStatus
+ [pscustomobject]@{
+ Application=$app.Application
+ Type="Orchestration"
+ Name=$o.Name
+ Status=$st.Text
+ }
+ }
+ }
+
+ $csvArtifact |
+ Export-Csv -Encoding UTF8 -NoTypeInformation -Path ($OutputFile + ".csv")
+
+ Export-HostInstancesCsv -HostInstances $hostInstances -CsvFile ($OutputFile + ".hosts.csv")
+
+ # HTML
+ $html=@()
+ $html+=""
+ $html+="BizTalk Snapshot
"
+
+ foreach ($app in $snapshot) {
+ $html+="Application: $($app.Application)
"
+
+ if ($app.ReceiveLocations.Count -gt 0) {
+ $html+="Receive Locations
| Name | Status |
"
+ foreach ($rl in $app.ReceiveLocations) {
+ $st = Format-Status -ArtifactType "ReceiveLocation" -Value $rl.Enabled
+ $html+="| $($rl.Name) | $($st.Text) |
"
+ }
+ $html+="
"
+ }
+
+ if ($app.SendPorts.Count -gt 0) {
+ $html+="Send Ports
| Name | Status |
"
+ foreach ($sp in $app.SendPorts) {
+ $st = Format-Status -ArtifactType "SendPort" -Value $sp.Status
+ $html+="| $($sp.Name) | $($st.Text) |
"
+ }
+ $html+="
"
+ }
+
+ if ($app.Orchestrations.Count -gt 0) {
+ $html+="Orchestrations
| Name | Status |
"
+ foreach ($o in $app.Orchestrations) {
+ $st = Format-Status -ArtifactType "Orchestration" -Value $o.OrchestrationStatus
+ $html+="| $($o.Name) | $($st.Text) |
"
+ }
+ $html+="
"
+ }
+ }
+
+ # Add Host Instances
+ $html += Export-HostInstancesHtml -HostInstances $hostInstances
+
+ $html+=""
+ $html -join "`n" | Out-File ($OutputFile + ".html") -Encoding UTF8
+
+ # Console Output
+ Write-Host "`n===== Snapshot =====" -ForegroundColor Yellow
+ foreach ($app in $snapshot) {
+ Write-Host "`nApplication: $($app.Application)" -ForegroundColor Cyan
+
+ foreach ($rl in $app.ReceiveLocations) {
+ $st = Format-Status -ArtifactType "ReceiveLocation" -Value $rl.Enabled
+ Write-Host (" RL {0,-60} {1}" -f $rl.Name,$st.Text) -ForegroundColor $st.ConsoleColor
+ }
+
+ foreach ($sp in $app.SendPorts) {
+ $st = Format-Status -ArtifactType "SendPort" -Value $sp.Status
+ Write-Host (" SP {0,-60} {1}" -f $sp.Name,$st.Text) -ForegroundColor $st.ConsoleColor
+ }
+
+ foreach ($o in $app.Orchestrations) {
+ $st = Format-Status -ArtifactType "Orchestration" -Value $o.OrchestrationStatus
+ Write-Host (" OR {0,-60} {1}" -f $o.Name,$st.Text) -ForegroundColor $st.ConsoleColor
+ }
+ }
+
+ Show-HostInstancesConsole -HostInstances $hostInstances
+
+ Write-Host "Snapshot erstellt: $(Resolve-Path $OutputFile)" -ForegroundColor Green
+}
+
+# ======================================================
+# COMPARE (Before/After)
+# ======================================================
+function Compare-BizTalkSnapshots {
+ param(
+ [string]$Before,
+ [string]$After,
+ [string]$HtmlReport = "BizTalkDiff.html"
+ )
+
+ $b = Get-Content $Before | ConvertFrom-Json
+ $a = Get-Content $After | ConvertFrom-Json
+
+ $diff = @()
+
+ function AddDiff {
+ param($app,$type,$name,$before,$after)
+
+ $bf = Format-Status -ArtifactType $type -Value $before
+ $af = Format-Status -ArtifactType $type -Value $after
+
+ $script:diff += [pscustomobject]@{
+ Application = $app
+ ArtifactType= $type
+ Name = $name
+ BeforeText = $bf.Text
+ BeforeClass = $bf.Class
+ AfterText = $af.Text
+ AfterClass = $af.Class
+ }
+ }
+
+ foreach ($appAfter in $a.Applications) {
+ $appBefore = $b.Applications | Where-Object {$_.Application -eq $appAfter.Application}
+
+ # RECEIVE LOCATIONS
+ foreach ($x in $appAfter.ReceiveLocations) {
+ $old = $appBefore.ReceiveLocations | Where-Object {$_.Name -eq $x.Name}
+ if (-not $old) { AddDiff $appAfter.Application "ReceiveLocation" $x.Name $null $x.Enabled; continue }
+ if ($old.Enabled -ne $x.Enabled) { AddDiff $appAfter.Application "ReceiveLocation" $x.Name $old.Enabled $x.Enabled }
+ }
+ foreach ($x in $appBefore.ReceiveLocations) {
+ if (-not ($appAfter.ReceiveLocations | Where-Object {$_.Name -eq $x.Name})) {
+ AddDiff $appBefore.Application "ReceiveLocation" $x.Name $x.Enabled $null
+ }
+ }
+
+ # SEND PORTS
+ foreach ($x in $appAfter.SendPorts) {
+ $old = $appBefore.SendPorts | Where-Object {$_.Name -eq $x.Name}
+ if (-not $old) { AddDiff $appAfter.Application "SendPort" $x.Name $null $x.Status; continue }
+ if ($old.Status -ne $x.Status) { AddDiff $appAfter.Application "SendPort" $x.Name $old.Status $x.Status }
+ }
+ foreach ($x in $appBefore.SendPorts) {
+ if (-not ($appAfter.SendPorts | Where-Object {$_.Name -eq $x.Name})) {
+ AddDiff $appBefore.Application "SendPort" $x.Name $x.Status $null
+ }
+ }
+
+ # ORCHESTRATIONS
+ foreach ($x in $appAfter.Orchestrations) {
+ $old = $appBefore.Orchestrations | Where-Object {$_.Name -eq $x.Name}
+ if (-not $old) { AddDiff $appAfter.Application "Orchestration" $x.Name $null $x.OrchestrationStatus; continue }
+ if ($old.OrchestrationStatus -ne $x.OrchestrationStatus) {
+ AddDiff $appAfter.Application "Orchestration" $x.Name $old.OrchestrationStatus $x.OrchestrationStatus
+ }
+ }
+ foreach ($x in $appBefore.Orchestrations) {
+ if (-not ($appAfter.Orchestrations | Where-Object {$_.Name -eq $x.Name})) {
+ AddDiff $appBefore.Application "Orchestration" $x.Name $x.OrchestrationStatus $null
+ }
+ }
+ }
+
+ # ======================================================
+ # HOST INSTANCE DIFF (Option H-DIFF2)
+ # ======================================================
+
+ $beforeHI = $b.HostInstances
+ $afterHI = $a.HostInstances
+
+ $hiDiff_New=@()
+ $hiDiff_Removed=@()
+ $hiDiff_Changed=@()
+
+ # New
+ foreach ($hi in $afterHI) {
+ if (-not ($beforeHI | Where-Object {$_.InstanceName -eq $hi.InstanceName})) {
+ $hiDiff_New += $hi
+ }
+ }
+
+ # Removed
+ foreach ($hi in $beforeHI) {
+ if (-not ($afterHI | Where-Object {$_.InstanceName -eq $hi.InstanceName})) {
+ $hiDiff_Removed += $hi
+ }
+ }
+
+ # Changed
+ foreach ($hiAfter in $afterHI) {
+ $hiBefore = $beforeHI | Where-Object {$_.InstanceName -eq $hiAfter.InstanceName}
+ if ($hiBefore) {
+ if ($hiBefore.StateText -ne $hiAfter.StateText) {
+ $hiDiff_Changed += [pscustomobject]@{
+ Instance = $hiAfter.InstanceName
+ Before = $hiBefore.StateText
+ After = $hiAfter.StateText
+ }
+ }
+ }
+ }
+
+ # ======================================================
+ # JSON DIFF EXPORT
+ # ======================================================
+ $jsonDiff = [pscustomobject]@{
+ ArtifactsDiff = $diff
+ HostInstances = [pscustomobject]@{
+ New = $hiDiff_New
+ Removed = $hiDiff_Removed
+ Changed = $hiDiff_Changed
+ }
+ }
+
+ $jsonDiff | ConvertTo-Json -Depth 8 | Out-File "diff.json" -Encoding UTF8
+
+ # ======================================================
+ # CSV DIFF EXPORT
+ # ======================================================
+ $diff | Export-Csv -Path "diff.csv" -NoTypeInformation -Encoding UTF8
+
+ # ======================================================
+ # HTML DIFF EXPORT
+ # ======================================================
+ $html=@()
+ $html+=""
+ $html+="BizTalk Differences
"
+
+ # Artifacts
+ $html+="Artifact Differences
"
+ $html+="| Application | Type | Name | Before | After |
"
+ foreach ($d in $diff) {
+ $html+="
+ | $($d.Application) |
+ $($d.ArtifactType) |
+ $($d.Name) |
+ $($d.BeforeText) |
+ $($d.AfterText) |
+
"
+ }
+ $html+="
"
+
+ # HostInstance DIFF
+ $html+="Host Instance Changes
"
+
+ # NEW
+ $html+="New
| Instance | Host | Server | Status |
"
+ foreach ($hi in $hiDiff_New) {
+ $html+="
+ | $($hi.InstanceName) |
+ $($hi.HostName) |
+ $($hi.Server) |
+ $($hi.StateText) |
+
"
+ }
+ $html+="
"
+
+ # REMOVED
+ $html+="Removed
| Instance | Host | Server | Status |
"
+ foreach ($hi in $hiDiff_Removed) {
+ $html+="
+ | $($hi.InstanceName) |
+ $($hi.HostName) |
+ $($hi.Server) |
+ $($hi.StateText) |
+
"
+ }
+ $html+="
"
+
+ # CHANGED
+ $html+="Changed
| Instance | Before | After |
"
+ foreach ($hi in $hiDiff_Changed) {
+ $before = Format-Status -ArtifactType "HostInstance" -Value $hi.Before
+ $after = Format-Status -ArtifactType "HostInstance" -Value $hi.After
+ $html+="
+ | $($hi.Instance) |
+ $($hi.Before) |
+ $($hi.After) |
+
"
+ }
+ $html+="
"
+
+ $html+=""
+ $html -join "`n" | Out-File $HtmlReport -Encoding UTF8
+
+ # ======================================================
+ # CONSOLE OUTPUT
+ # ======================================================
+ Write-Host "`n===== BizTalk DIFF =====" -ForegroundColor Yellow
+
+ if ($diff.Count -eq 0 -and
+ $hiDiff_New.Count -eq 0 -and
+ $hiDiff_Removed.Count -eq 0 -and
+ $hiDiff_Changed.Count -eq 0)
+ {
+ Write-Host "Keine Unterschiede." -ForegroundColor Green
+ }
+ else {
+ Write-Host "`n--- Artifacts ---" -ForegroundColor Cyan
+ foreach ($d in $diff) {
+ Write-Host "`nApplication: $($d.Application)" -ForegroundColor Cyan
+ Write-Host "Artifact: $($d.ArtifactType)"
+ Write-Host "Name: $($d.Name)"
+ Write-Host ("Before: {0}" -f $d.BeforeText) -ForegroundColor $(
+ if ($d.BeforeClass -eq "ok") {"Green"} elseif ($d.BeforeClass -eq "warn") {"Yellow"} else {"Red"})
+ Write-Host ("After: {0}" -f $d.AfterText) -ForegroundColor $(
+ if ($d.AfterClass -eq "ok") {"Green"} elseif ($d.AfterClass -eq "warn") {"Yellow"} else {"Red"})
+ }
+
+ Write-Host "`n--- Host Instances (New) ---" -ForegroundColor Cyan
+ foreach ($hi in $hiDiff_New) {
+ Write-Host ("NEW: {0} {1}" -f $hi.InstanceName,$hi.StateText) -ForegroundColor $hi.ConsoleColor
+ }
+
+ Write-Host "`n--- Host Instances (Removed) ---" -ForegroundColor Cyan
+ foreach ($hi in $hiDiff_Removed) {
+ Write-Host ("REMOVED: {0} {1}" -f $hi.InstanceName,$hi.StateText) -ForegroundColor Red
+ }
+
+ Write-Host "`n--- Host Instances (Changed) ---" -ForegroundColor Cyan
+ foreach ($hi in $hiDiff_Changed) {
+ Write-Host ("CHANGED: {0} {1} -> {2}" -f $hi.Instance,$hi.Before,$hi.After) -ForegroundColor Yellow
+ }
+ }
+
+ Write-Host "HTML Diff exportiert: $HtmlReport" -ForegroundColor Green
+}
+
+# ======================================================
+# DISPATCH
+# ======================================================
+if (-not (Test-Path $OutDir)) {
+ New-Item -ItemType Directory -Path $OutDir | Out-Null
+}
+Set-Location $OutDir
+Write-Log "Working dir: $(Get-Location)"
+
+if ($Diag) {
+ Write-Host "DIAG → Server: $Server" -ForegroundColor Yellow
+ try {
+ $sp = Get-WmiObject MSBTS_SendPort -Namespace root\MicrosoftBizTalkServer -ComputerName $Server |
+ Select -First 3 Name,Status
+ Write-Host "WMI OK:" -ForegroundColor Green
+ $sp | Format-Table
+ }
+ catch {
+ Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
+ }
+ exit
+}
+
+if ($Before) { Get-BizTalkSnapshot -OutputFile "before.json" -Server $Server -MgmtDbServer $MgmtDbServer -MgmtDbName $MgmtDbName; exit }
+if ($After) { Get-BizTalkSnapshot -OutputFile "after.json" -Server $Server -MgmtDbServer $MgmtDbServer -MgmtDbName $MgmtDbName; exit }
+if ($Compare){ Compare-BizTalkSnapshots -Before "before.json" -After "after.json"; exit }
+
+Write-Host "Usage:"
+Write-Host " .\BizTalkStatusTool.ps1 -Before"
+Write-Host " .\BizTalkStatusTool.ps1 -After"
+Write-Host " .\BizTalkStatusTool.ps1 -Compare"
+Write-Host " .\BizTalkStatusTool.ps1 -Diag"
\ No newline at end of file