Harden BizTalk maintenance workflow and add installer

This commit is contained in:
2026-08-06 18:46:28 +02:00
parent e8df6042d2
commit 0cb3fda151
32 changed files with 1782 additions and 565 deletions
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.props" Condition="Exists('$(MSBuildToolsPath)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{38E61630-11AB-4F8D-B421-F8A88831C4BD}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>BizTalkPlatformManagementTool.Setup</RootNamespace>
<AssemblyName>BizTalkPlatformManagementTool.Setup</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<ApplicationManifest>app.manifest</ApplicationManifest>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols><DebugType>full</DebugType><Optimize>false</Optimize><OutputPath>bin\Debug\</OutputPath><DefineConstants>DEBUG;TRACE</DefineConstants><WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType><Optimize>true</Optimize><OutputPath>bin\Release\</OutputPath><DefineConstants>TRACE</DefineConstants><WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" /><Reference Include="System.Core" /><Reference Include="System.Drawing" /><Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="InstallerEngine.cs" /><Compile Include="MainForm.cs" /><Compile Include="Program.cs" /><None Include="app.manifest" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BizTalkPlatformManagementTool\BizTalkPlatformManagementTool.csproj"><Project>{2C5B2C0A-F407-46C2-9E3B-1FA09FA8445A}</Project><Name>BizTalkPlatformManagementTool</Name><ReferenceOutputAssembly>false</ReferenceOutputAssembly></ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
namespace BizTalkPlatformManagementTool.Setup
{
internal sealed class InstallerEngine
{
private const string ProductName = "BizTalkPlatformManagementTool";
private readonly string _packageDirectory;
private readonly string _installDirectory;
private readonly string _runtimeDirectory;
public InstallerEngine(string packageDirectory)
{
_packageDirectory = Path.GetFullPath(packageDirectory);
_installDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), ProductName);
_runtimeDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), ProductName);
}
public bool IsInstalled
{
get { return File.Exists(Path.Combine(_installDirectory, "BizTalkPlatformManagementTool.exe")); }
}
public void Install(bool createDesktopShortcut, Action<string> report)
{
report = report ?? delegate { };
var source = Path.Combine(_packageDirectory, "application");
var sourceExe = Path.Combine(source, "BizTalkPlatformManagementTool.exe");
RequireFile(sourceExe);
RequireFile(sourceExe + ".config");
var assembly = AssemblyName.GetAssemblyName(sourceExe);
report("Paket geprüft: Version " + assembly.Version + ".");
var staging = _installDirectory + ".staging." + Guid.NewGuid().ToString("N");
var backup = _installDirectory + ".backup." + Guid.NewGuid().ToString("N");
var hadInstallation = Directory.Exists(_installDirectory);
var backupCreated = false;
var activated = false;
try
{
CopyDirectory(source, staging);
AssemblyName.GetAssemblyName(Path.Combine(staging, "BizTalkPlatformManagementTool.exe"));
report("Neue Version im Staging-Verzeichnis validiert.");
if (hadInstallation)
{
Directory.Move(_installDirectory, backup);
backupCreated = true;
}
Directory.Move(staging, _installDirectory);
activated = true;
Directory.CreateDirectory(Path.Combine(_runtimeDirectory, "Wartungen"));
Directory.CreateDirectory(Path.Combine(_runtimeDirectory, "Logs"));
CreateShortcuts(createDesktopShortcut);
report(hadInstallation ? "Programmdateien sicher aktualisiert." : "Programmdateien installiert.");
report("Arbeitsdaten bleiben unter " + _runtimeDirectory + ".");
TryDeleteDirectory(backup);
}
catch (Exception ex)
{
var rollbackErrors = new List<string>();
try
{
if (activated && Directory.Exists(_installDirectory)) Directory.Delete(_installDirectory, true);
if (backupCreated && Directory.Exists(backup)) Directory.Move(backup, _installDirectory);
}
catch (Exception rollback)
{
rollbackErrors.Add(rollback.Message);
}
throw new InvalidOperationException(
"Installation/Update fehlgeschlagen. "
+ (rollbackErrors.Count == 0 ? "Die vorherige Version wurde wiederhergestellt. " : "Rollbackfehler: " + string.Join(" | ", rollbackErrors) + ". ")
+ "Ursache: " + ex.Message,
ex);
}
finally
{
TryDeleteDirectory(staging);
}
}
public void Uninstall(bool keepRuntimeData, Action<string> report)
{
report = report ?? delegate { };
DeleteShortcuts();
if (Directory.Exists(_installDirectory)) Directory.Delete(_installDirectory, true);
if (!keepRuntimeData && Directory.Exists(_runtimeDirectory)) Directory.Delete(_runtimeDirectory, true);
report(keepRuntimeData
? "Programm entfernt; Wartungszustände und Logs wurden beibehalten."
: "Programm und Arbeitsdaten wurden entfernt.");
}
private void CreateShortcuts(bool desktop)
{
var target = Path.Combine(_installDirectory, "BizTalkPlatformManagementTool.exe");
var programs = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms), "JR IT Services");
Directory.CreateDirectory(programs);
WriteInternetShortcut(Path.Combine(programs, "BizTalk Platform Management Tool.url"), target);
var desktopPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDesktopDirectory), "BizTalk Platform Management Tool.url");
if (desktop) WriteInternetShortcut(desktopPath, target); else if (File.Exists(desktopPath)) File.Delete(desktopPath);
}
private static void WriteInternetShortcut(string path, string target)
{
var uri = new Uri(target).AbsoluteUri;
var content = "[InternetShortcut]\r\nURL=" + uri + "\r\nIconFile=" + target + "\r\nIconIndex=0\r\n";
File.WriteAllText(path, content, new UTF8Encoding(false));
}
private static void DeleteShortcuts()
{
var start = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms), "JR IT Services", "BizTalk Platform Management Tool.url");
var desktop = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDesktopDirectory), "BizTalk Platform Management Tool.url");
if (File.Exists(start)) File.Delete(start);
if (File.Exists(desktop)) File.Delete(desktop);
}
private static void CopyDirectory(string source, string destination)
{
Directory.CreateDirectory(destination);
foreach (var file in Directory.GetFiles(source))
File.Copy(file, Path.Combine(destination, Path.GetFileName(file)), false);
foreach (var directory in Directory.GetDirectories(source))
CopyDirectory(directory, Path.Combine(destination, Path.GetFileName(directory)));
}
private static void RequireFile(string path)
{
if (!File.Exists(path)) throw new FileNotFoundException("Installationspaket ist unvollständig. Datei fehlt: " + path, path);
}
private static void TryDeleteDirectory(string path)
{
if (!Directory.Exists(path)) return;
try { Directory.Delete(path, true); }
catch { }
}
}
}
@@ -0,0 +1,148 @@
using System;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BizTalkPlatformManagementTool.Setup
{
internal sealed class MainForm : Form
{
private readonly InstallerEngine _engine;
private readonly CheckBox _desktop = new CheckBox();
private readonly CheckBox _keepData = new CheckBox();
private readonly Button _install = new Button();
private readonly Button _uninstall = new Button();
private readonly TextBox _status = new TextBox();
public MainForm(InstallerEngine engine)
{
_engine = engine;
Text = "BizTalk Platform Management Tool Setup";
ClientSize = new Size(680, 500);
MinimumSize = new Size(696, 539);
StartPosition = FormStartPosition.CenterScreen;
AutoScaleMode = AutoScaleMode.Dpi;
Font = new Font("Segoe UI", 9F);
BackColor = Color.White;
BuildUi();
}
private void BuildUi()
{
var header = new Panel { Dock = DockStyle.Top, Height = 112, BackColor = Color.FromArgb(28, 67, 102) };
header.Controls.Add(new Label { Text = "BizTalk Platform Management Tool", Location = new Point(24, 20), Size = new Size(620, 34), ForeColor = Color.White, Font = new Font(Font.FontFamily, 17F, FontStyle.Bold) });
header.Controls.Add(new Label { Text = "Installieren oder sicher auf eine neue Version aktualisieren", Location = new Point(26, 62), Size = new Size(620, 25), ForeColor = Color.FromArgb(220, 232, 242) });
Controls.Add(header);
var body = new TableLayoutPanel { Dock = DockStyle.Fill, Padding = new Padding(24, 18, 24, 18), ColumnCount = 2, RowCount = 5 };
body.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50));
body.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50));
body.RowStyles.Add(new RowStyle(SizeType.Absolute, 48));
body.RowStyles.Add(new RowStyle(SizeType.Absolute, 36));
body.RowStyles.Add(new RowStyle(SizeType.Absolute, 36));
body.RowStyles.Add(new RowStyle(SizeType.Absolute, 54));
body.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
Controls.Add(body);
body.Controls.Add(new Label
{
Text = _engine.IsInstalled
? "Eine vorhandene Installation wurde erkannt. Arbeitsdaten bleiben beim Update erhalten."
: "Bereit zur Installation. Setup muss aus dem vollständig entpackten Paket gestartet werden.",
Dock = DockStyle.Fill,
TextAlign = ContentAlignment.MiddleLeft
}, 0, 0);
body.SetColumnSpan(body.GetControlFromPosition(0, 0), 2);
_desktop.Text = "Desktop-Verknüpfung erstellen";
_desktop.Checked = true;
_desktop.Dock = DockStyle.Fill;
body.Controls.Add(_desktop, 0, 1);
body.SetColumnSpan(_desktop, 2);
_keepData.Text = "Wartungszustände und Logs bei Deinstallation behalten";
_keepData.Checked = true;
_keepData.Dock = DockStyle.Fill;
body.Controls.Add(_keepData, 0, 2);
body.SetColumnSpan(_keepData, 2);
ConfigureButton(_install, "Installieren / aktualisieren", Color.FromArgb(31, 111, 181));
ConfigureButton(_uninstall, "Deinstallieren", Color.FromArgb(120, 55, 55));
_install.Click += async delegate { await InstallAsync(); };
_uninstall.Click += async delegate { await UninstallAsync(); };
body.Controls.Add(_install, 0, 3);
body.Controls.Add(_uninstall, 1, 3);
_status.Dock = DockStyle.Fill;
_status.Multiline = true;
_status.ReadOnly = true;
_status.ScrollBars = ScrollBars.Vertical;
_status.BackColor = Color.FromArgb(247, 249, 252);
_status.BorderStyle = BorderStyle.FixedSingle;
body.Controls.Add(_status, 0, 4);
body.SetColumnSpan(_status, 2);
_uninstall.Enabled = _engine.IsInstalled;
}
private async Task InstallAsync()
{
SetBusy(true);
try
{
await Task.Run(() => _engine.Install(_desktop.Checked, Report));
Report("Installation erfolgreich abgeschlossen.");
MessageBox.Show(this, "Installation/Update erfolgreich abgeschlossen.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
Report("FEHLER: " + ex.Message);
MessageBox.Show(this, ex.Message, "Installation fehlgeschlagen", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally { SetBusy(false); }
}
private async Task UninstallAsync()
{
if (MessageBox.Show(this, "BizTalk Platform Management Tool wirklich deinstallieren?", Text, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) != DialogResult.Yes) return;
SetBusy(true);
try
{
await Task.Run(() => _engine.Uninstall(_keepData.Checked, Report));
MessageBox.Show(this, "Deinstallation abgeschlossen.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
Report("FEHLER: " + ex.Message);
MessageBox.Show(this, ex.Message, "Deinstallation fehlgeschlagen", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally { SetBusy(false); }
}
private void Report(string message)
{
if (InvokeRequired) { BeginInvoke(new Action<string>(Report), message); return; }
_status.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "] " + message + Environment.NewLine);
}
private void SetBusy(bool busy)
{
if (InvokeRequired) { BeginInvoke(new Action<bool>(SetBusy), busy); return; }
_install.Enabled = !busy;
_uninstall.Enabled = !busy && _engine.IsInstalled;
_desktop.Enabled = !busy;
_keepData.Enabled = !busy;
UseWaitCursor = busy;
}
private static void ConfigureButton(Button button, string text, Color color)
{
button.Text = text;
button.Dock = DockStyle.Fill;
button.Margin = new Padding(4, 7, 4, 7);
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderSize = 0;
button.BackColor = color;
button.ForeColor = Color.White;
button.Font = new Font("Segoe UI", 9F, FontStyle.Bold);
}
}
}
@@ -0,0 +1,16 @@
using System;
using System.Windows.Forms;
namespace BizTalkPlatformManagementTool.Setup
{
internal static class Program
{
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm(new InstallerEngine(AppDomain.CurrentDomain.BaseDirectory)));
}
}
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="BizTalkPlatformManagementTool.Setup" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>