Initial version BizTalkStatus Tool.

This commit is contained in:
2026-02-02 13:18:48 +01:00
commit cff972a0bf
8 changed files with 395 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
* text=auto eol=crlf

18
.gitignore vendored Normal file
View File

@@ -0,0 +1,18 @@
# OS / IDE
Thumbs.db
.DS_Store
.vscode/
.idea/
*.user
*.suo
# Logs / Outputs
*.log
*.json
*.html
work/
release/*
# PowerShell specifics
*.ps1.orig

21
CHANGELOG.md Normal file
View File

@@ -0,0 +1,21 @@
# Changelog
## [1.3.0] - 2026-02-02
### Added
- HTML Report mit farblicher Kennzeichnung (grün/rot)
- Farbige Statusausgabe auf STDOUT
- RemoteServer Parameter (-Server) und Ausgabeverzeichnis (-OutDir)
- Verbesserte DiffErkennung (neu/entfernt)
## [1.2.0] - 2026-02-02
### Added
- Remotefähige SnapshotFunktion, Logging (Konsole + Datei)
## [1.1.0] - 2026-02-02
### Added
- Textuelle DiffAusgabe auf STDOUT + HTML Report
## [1.0.0] - 2026-02-02
### Added
- Grundfunktion: Snapshot & Diff (Receive Locations, Send Ports, Orchestrations)

18
LICENSE Normal file
View File

@@ -0,0 +1,18 @@
MIT License
Copyright (c) 2026
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

37
README.md Normal file
View File

@@ -0,0 +1,37 @@
# BizTalk Status Tool (PowerShell only)
**Version:** 1.3.0
**Kompatibel mit:** Windows Server 2019, PowerShell 5.1, BizTalk Server 2020
## Features
- Snapshots **vor**/**nach** Downtime als JSON
- **Diff** zwischen Snapshots (nur Änderungen)
- **HTMLReport** mit **Farben** (grün = Started/Enabled, rot = Stopped/Disabled/Unbound/Bound)
- **Remotefähig**: `-Server` Parameter (WMI unter `root\MicrosoftBizTalkServer`)
- **Logging**: Konsole + `BizTalkStatusTool.log`
## Verwendung (Beispiele)
```powershell
# Snapshot VOR Downtime vom RemoteServer
.\src\BizTalkStatusTool.ps1 -Before -Server "BTAPP01" -OutDir .\work
# Snapshot NACH Downtime
.\src\BizTalkStatusTool.ps1 -After -Server "BTAPP01" -OutDir .\work
# Diff erstellen (Text + HTML im gleichen Ordner)
cd .\work
..\src\BizTalkStatusTool.ps1 -Compare
```
## StatusMapping
- **SendPort.Status**: 1=Bound, 2=Stopped, 3=Started
- **Orchestration.OrchestrationStatus**: 1=Unbound, 2=Bound, 3=Stopped, 4=Started
- **ReceiveLocation**: `Enabled = -not IsDisabled`
**Hinweis:** Diese Mappings stammen aus der offiziellen BizTalkDokumentation (siehe `REFERENCES.md`).
## Releases
Fertige Skripte liegen im Ordner `/release`.
## Tags
Mit `tools/Create-Tags.ps1` kannst du lokale GitTags (`v1.0.0`, `v1.1.0`, `v1.2.0`, `v1.3.0`) erstellen.

7
REFERENCES.md Normal file
View File

@@ -0,0 +1,7 @@
# References
- MSBTS_SendPort.Status (WMI): https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-sendport-status-property-wmi
- MSBTS_SendPort (WMI): https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-sendport-wmi
- MSBTS_Orchestration.OrchestrationStatus (WMI): https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-orchestration-orchestrationstatus-property-wmi
- MSBTS_ReceiveLocation (WMI): https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-receivelocation-wmi

278
src/BizTalkStatusTool.ps1 Normal file
View File

@@ -0,0 +1,278 @@
<#!
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
#>
$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 = @"
<html>
<head>
<title>BizTalk Differences Report</title>
<style>
body { font-family: Arial, Helvetica, sans-serif; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #999; padding: 8px; text-align: left; }
th { background-color: #2d6cdf; color: white; }
tr:nth-child(even) { background-color: #f8f8f8; }
.ok { color: #0a7d00; font-weight: 600; }
.bad { color: #b00020; font-weight: 600; }
.neutral { color: #b58900; font-weight: 600; }
.small { color:#666; font-size:12px; }
</style>
</head>
<body>
<h2>BizTalk Differences Report</h2>
<p class="small">Vergleich: <b>$Before</b> <b>$After</b></p>
<table>
<tr>
<th>Application</th>
<th>Artifact</th>
<th>Name</th>
<th>Before</th>
<th>After</th>
</tr>
"@
$rows = foreach ($d in $differences) {
"<tr><td>$($d.Application)</td><td>$($d.ArtifactType)</td><td>$($d.Name)</td><td class='${($d.BeforeClass)}'>$($d.BeforeText)</td><td class='${($d.AfterClass)}'>$($d.AfterText)</td></tr>"
}
$htmlFooter = "</table></body></html>"
($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) ----------------
param(
[switch]$Before,
[switch]$After,
[switch]$Compare,
[string]$Server = $env:COMPUTERNAME,
[string]$OutDir = '.'
)
if ($PSBoundParameters.ContainsKey('OutDir')) { New-Item -ItemType Directory -Force -Path $OutDir | Out-Null; Set-Location $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 <BizTalkServer> -OutDir <Pfad>"
Write-Host " Snapshot nach Downtime: .\BizTalkStatusTool.ps1 -After -Server <BizTalkServer> -OutDir <Pfad>"
Write-Host " Diff + HTML Report: .\BizTalkStatusTool.ps1 -Compare"
}

14
tools/Create-Tags.ps1 Normal file
View File

@@ -0,0 +1,14 @@
param(
[string]$TagPrefix = 'v'
)
if (!(Get-Command git -ErrorAction SilentlyContinue)) { Write-Host 'git ist nicht installiert oder nicht im PATH.'; exit 1 }
# Initialisiert ein Repo, committet und erstellt Tags
& git init
& git add .
& git commit -m "Initial import (v1.3.0)"
& git tag "${TagPrefix}1.0.0" -m "Baseline"
& git tag "${TagPrefix}1.1.0" -m "Textdiff + HTML"
& git tag "${TagPrefix}1.2.0" -m "Remote + Logging"
& git tag "${TagPrefix}1.3.0" -m "Farben + Releases"
Write-Host "Tags erstellt: ${TagPrefix}1.0.0, ${TagPrefix}1.1.0, ${TagPrefix}1.2.0, ${TagPrefix}1.3.0"