Isolate optional desktop shortcut failures

This commit is contained in:
2026-08-24 13:02:58 +02:00
parent 3219c3f1bc
commit 3b4a621cd3
16 changed files with 311 additions and 45 deletions
@@ -23,7 +23,7 @@ namespace BizTalkPlatformManagementTool.Setup
private const string ProductName = "BizTalk Platform Management Tool";
/// <summary>Aktuelle Produktversion des Installers und Uninstall-Eintrags.</summary>
private const string ProductVersion = "2.2.3";
private const string ProductVersion = "2.2.4";
/// <summary>
/// Wartezeiten zwischen Wiederholungen atomarer Verzeichnisverschiebungen.
@@ -71,6 +71,9 @@ namespace BizTalkPlatformManagementTool.Setup
/// <summary>Ruft den vorherigen Inhalt der Desktop-Verknüpfung ab oder legt ihn fest.</summary>
public byte[] DesktopShortcut { get; set; }
/// <summary>Ruft ab oder legt fest, ob der optionale Desktop-Zustand sicher gelesen wurde.</summary>
public bool DesktopShortcutCaptured { get; set; }
/// <summary>Ruft den vorherigen Inhalt der Startmenü-Verknüpfung ab oder legt ihn fest.</summary>
public byte[] StartMenuShortcut { get; set; }
@@ -155,6 +158,7 @@ namespace BizTalkPlatformManagementTool.Setup
var uiReport = report ?? delegate { };
var log = SetupOperationLog.Create(dataDirectory, "install-update");
Action<string> write = message => ReportSafely(log, uiReport, "INFO", message);
Action<string> warn = message => ReportSafely(log, uiReport, "WARN", message);
if (!string.IsNullOrEmpty(log.CreationError))
write((log.IsFallback ? "WARNUNG: Primaeres Diagnoselog nicht verfuegbar; Temp-Fallback wird verwendet: " : "WARNUNG: Diagnoselog konnte nicht angelegt werden: ") + log.CreationError);
if (log.FilePath.Length != 0)
@@ -175,6 +179,7 @@ namespace BizTalkPlatformManagementTool.Setup
var activated = false;
var activationUsedCopyFallback = false;
var integrationMutationStarted = false;
var optionalDesktopShortcutWarning = false;
var phaseCode = "SETUP-INITIALIZATION";
var phase = "Initialisierung";
@@ -197,13 +202,17 @@ namespace BizTalkPlatformManagementTool.Setup
log.WriteFileDetails("setup_executable", Assembly.GetExecutingAssembly().Location);
log.WriteFileDetails("existing_application", Path.Combine(installDirectory, ApplicationExeName));
// Der vollständige Integrationszustand wird vor der ersten Mutation gesichert.
integrationSnapshot = registerWindowsIntegration ? CaptureWindowsIntegration() : null;
integrationSnapshot = registerWindowsIntegration ? CaptureWindowsIntegration(log, warn) : null;
if (integrationSnapshot != null)
{
optionalDesktopShortcutWarning = !integrationSnapshot.DesktopShortcutCaptured;
log.Write("INFO", "event=integration_snapshot registry_key_existed=" + integrationSnapshot.RegistryKeyExisted
+ " registry_value_count=" + integrationSnapshot.RegistryValues.Count
+ " desktop_shortcut_captured=" + integrationSnapshot.DesktopShortcutCaptured
+ " desktop_shortcut=" + (integrationSnapshot.DesktopShortcut != null)
+ " start_menu_shortcut=" + (integrationSnapshot.StartMenuShortcut != null)
+ " uninstaller=" + (integrationSnapshot.Uninstaller != null));
}
phaseCode = "SETUP-PACKAGE-VALIDATION";
phase = "Paketmanifest und SHA-256 pruefen";
@@ -277,8 +286,9 @@ namespace BizTalkPlatformManagementTool.Setup
if (registerWindowsIntegration)
{
integrationMutationStarted = true;
RegisterWindowsIntegration(targetExe, createDesktopShortcut);
ValidateWindowsIntegration(targetExe, createDesktopShortcut, log);
var desktopConfigured = RegisterWindowsIntegration(targetExe, createDesktopShortcut, log, warn);
var desktopValidated = ValidateWindowsIntegration(targetExe, createDesktopShortcut, log, warn);
optionalDesktopShortcutWarning = optionalDesktopShortcutWarning || !desktopConfigured || !desktopValidated;
}
phaseCode = "SETUP-CLEANUP";
@@ -287,11 +297,15 @@ namespace BizTalkPlatformManagementTool.Setup
var backupCleanupSucceeded = TryDeleteDirectory(backupDirectory, write);
var stagingCleanupSucceeded = TryDeleteDirectory(stagingDirectory, write);
var cleanupSucceeded = backupCleanupSucceeded && stagingCleanupSucceeded;
var completionResult = cleanupSucceeded
? (optionalDesktopShortcutWarning ? "success_with_optional_desktop_shortcut_warning" : "success")
: (optionalDesktopShortcutWarning ? "success_with_multiple_warnings" : "success_with_temporary_cleanup_warning");
log.Write(
cleanupSucceeded ? "INFO" : "WARN",
"event=setup_completed result=" + (cleanupSucceeded ? "success" : "success_with_temporary_cleanup_warning")
cleanupSucceeded && !optionalDesktopShortcutWarning ? "INFO" : "WARN",
"event=setup_completed result=" + completionResult
+ " backup_directory_preserved=" + Directory.Exists(backupDirectory)
+ " staging_directory_preserved=" + Directory.Exists(stagingDirectory)
+ " optional_desktop_shortcut_warning=" + optionalDesktopShortcutWarning
+ " activation_method=" + (activationUsedCopyFallback ? "verified_copy_fallback" : "atomic_move")
+ " install_directory=\"" + installDirectory + "\"");
write("Installation/Update erfolgreich abgeschlossen: " + installDirectory);
@@ -340,7 +354,7 @@ namespace BizTalkPlatformManagementTool.Setup
if (registerWindowsIntegration && integrationSnapshot != null)
{
log.Write("WARN", "event=rollback_step step=restore_windows_integration");
RestoreWindowsIntegration(integrationSnapshot);
RestoreWindowsIntegration(integrationSnapshot, log, warn);
log.Write("WARN", "event=rollback_step_complete step=windows_integration result=success");
}
}
@@ -380,6 +394,7 @@ namespace BizTalkPlatformManagementTool.Setup
var uiReport = report ?? delegate { };
var log = SetupOperationLog.Create(dataDirectory, "uninstall");
Action<string> write = message => ReportSafely(log, uiReport, "INFO", message);
Action<string> warn = message => ReportSafely(log, uiReport, "WARN", message);
if (!string.IsNullOrEmpty(log.CreationError))
write((log.IsFallback ? "WARNUNG: Primaeres Diagnoselog nicht verfuegbar; Temp-Fallback wird verwendet: " : "WARNUNG: Diagnoselog konnte nicht angelegt werden: ") + log.CreationError);
if (log.FilePath.Length != 0)
@@ -388,6 +403,7 @@ namespace BizTalkPlatformManagementTool.Setup
write("Diagnoselog: " + log.FilePath);
}
WindowsIntegrationSnapshot integrationSnapshot = null;
var optionalDesktopShortcutWarning = false;
var removalDirectory = installDirectory + ".removed." + Guid.NewGuid().ToString("N");
var filesMoved = false;
var phaseCode = "UNINSTALL-INITIALIZATION";
@@ -397,7 +413,9 @@ namespace BizTalkPlatformManagementTool.Setup
Directory.CreateDirectory(dataDirectory);
log.Write("INFO", "event=uninstall_context install_directory=\"" + installDirectory + "\" removal_directory=\"" + removalDirectory + "\" data_directory=\"" + dataDirectory + "\"");
log.WriteFileDetails("installed_application", Path.Combine(installDirectory, ApplicationExeName));
integrationSnapshot = registerWindowsIntegration ? CaptureWindowsIntegration() : null;
integrationSnapshot = registerWindowsIntegration ? CaptureWindowsIntegration(log, warn) : null;
if (integrationSnapshot != null)
optionalDesktopShortcutWarning = !integrationSnapshot.DesktopShortcutCaptured;
phaseCode = "UNINSTALL-RUNNING-APPLICATION";
phase = "Laufende Anwendung ausschliessen";
@@ -420,10 +438,14 @@ namespace BizTalkPlatformManagementTool.Setup
phaseCode = "UNINSTALL-WINDOWS-INTEGRATION";
phase = "Windows-Integration entfernen";
write("Phase 3/3: " + phase + ".");
if (registerWindowsIntegration) RemoveWindowsIntegration(log);
optionalDesktopShortcutWarning = optionalDesktopShortcutWarning || (registerWindowsIntegration && !RemoveWindowsIntegration(log, warn));
var cleanupSucceeded = TryDeleteDirectory(removalDirectory, write);
log.Write("INFO", "event=uninstall_completed result=" + (cleanupSucceeded ? "success" : "success_with_quarantine_cleanup_warning")
+ " removal_directory_preserved=" + Directory.Exists(removalDirectory));
var completionResult = cleanupSucceeded
? (optionalDesktopShortcutWarning ? "success_with_optional_desktop_shortcut_warning" : "success")
: (optionalDesktopShortcutWarning ? "success_with_multiple_warnings" : "success_with_quarantine_cleanup_warning");
log.Write(cleanupSucceeded && !optionalDesktopShortcutWarning ? "INFO" : "WARN", "event=uninstall_completed result=" + completionResult
+ " removal_directory_preserved=" + Directory.Exists(removalDirectory)
+ " optional_desktop_shortcut_warning=" + optionalDesktopShortcutWarning);
write("Deinstallation erfolgreich. Installer-Logs bleiben erhalten: " + Path.Combine(dataDirectory, "InstallerLogs"));
}
catch (Exception ex)
@@ -447,7 +469,7 @@ namespace BizTalkPlatformManagementTool.Setup
{
try
{
RestoreWindowsIntegration(integrationSnapshot);
RestoreWindowsIntegration(integrationSnapshot, log, warn);
log.Write("WARN", "event=uninstall_rollback_step step=restore_windows_integration result=success");
}
catch (Exception rollbackException)
@@ -470,14 +492,26 @@ namespace BizTalkPlatformManagementTool.Setup
/// </summary>
/// <param name="targetExe">Der vollständige Pfad der aktivierten Anwendung.</param>
/// <param name="createDesktopShortcut"><c>true</c>, wenn eine Desktop-Verknüpfung gewünscht ist.</param>
private void RegisterWindowsIntegration(string targetExe, bool createDesktopShortcut)
/// <param name="log">Das Diagnoseprotokoll des aktuellen Setup-Laufs.</param>
/// <param name="warn">Die ausfallsichere Bedienerwarnung.</param>
/// <returns><c>true</c>, wenn der optionale Desktop-Zustand ohne Fehler gesetzt wurde.</returns>
private bool RegisterWindowsIntegration(string targetExe, bool createDesktopShortcut, SetupOperationLog log, Action<string> warn)
{
var programsDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms), ProductName);
Directory.CreateDirectory(programsDirectory);
CreateShortcut(Path.Combine(programsDirectory, ProductName + ".lnk"), targetExe, installDirectory, ProductName);
if (createDesktopShortcut) CreateShortcut(DesktopShortcutPath, targetExe, installDirectory, ProductName);
else if (File.Exists(DesktopShortcutPath)) File.Delete(DesktopShortcutPath);
var desktopConfigured = TryOptionalWindowsIntegrationStep(
createDesktopShortcut ? "desktop_shortcut_create" : "desktop_shortcut_remove",
"Desktop-Verknuepfung fuer alle Benutzer " + (createDesktopShortcut ? "erstellen" : "entfernen"),
DesktopShortcutPath,
() =>
{
if (createDesktopShortcut) CreateShortcut(DesktopShortcutPath, targetExe, installDirectory, ProductName);
else DeleteFileIfExists(DesktopShortcutPath);
},
log,
warn);
var setupDirectory = Path.Combine(dataDirectory, "Setup");
Directory.CreateDirectory(setupDirectory);
@@ -496,25 +530,40 @@ namespace BizTalkPlatformManagementTool.Setup
key.SetValue("NoModify", 1, RegistryValueKind.DWord);
key.SetValue("NoRepair", 1, RegistryValueKind.DWord);
}
return desktopConfigured;
}
/// <summary>
/// Entfernt und verifiziert die vom Setup verwaltete Windows-Integration.
/// </summary>
/// <param name="log">Das Diagnoseprotokoll des aktuellen Setup-Laufs.</param>
private void RemoveWindowsIntegration(SetupOperationLog log)
/// <param name="warn">Die ausfallsichere Bedienerwarnung.</param>
/// <returns><c>true</c>, wenn der optionale Desktop-Link entfernt oder bereits nicht vorhanden war.</returns>
private bool RemoveWindowsIntegration(SetupOperationLog log, Action<string> warn)
{
DeleteFileIfExists(DesktopShortcutPath);
var desktopRemoved = TryOptionalWindowsIntegrationStep(
"desktop_shortcut_uninstall_remove",
"Desktop-Verknuepfung fuer alle Benutzer bei der Deinstallation entfernen",
DesktopShortcutPath,
() =>
{
DeleteFileIfExists(DesktopShortcutPath);
if (File.Exists(DesktopShortcutPath))
throw new InvalidOperationException("Desktop shortcut still exists after removal.");
},
log,
warn);
var programsDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms), ProductName);
DeleteFileIfExists(Path.Combine(programsDirectory, ProductName + ".lnk"));
if (Directory.Exists(programsDirectory) && Directory.GetFileSystemEntries(programsDirectory).Length == 0) Directory.Delete(programsDirectory);
Registry.LocalMachine.DeleteSubKeyTree(UninstallKeyPath, false);
using (var remainingKey = Registry.LocalMachine.OpenSubKey(UninstallKeyPath, false))
{
if (File.Exists(DesktopShortcutPath) || File.Exists(StartMenuShortcutPath) || remainingKey != null)
if (File.Exists(StartMenuShortcutPath) || remainingKey != null)
throw new InvalidOperationException("Windows integration removal verification failed.");
}
log.Write("INFO", "event=windows_integration_removed registry_key=\"HKLM\\" + UninstallKeyPath + "\"");
log.Write("INFO", "event=windows_integration_removed registry_key=\"HKLM\\" + UninstallKeyPath + "\" optional_desktop_shortcut_removed=" + desktopRemoved);
return desktopRemoved;
}
/// <summary>
@@ -553,16 +602,24 @@ namespace BizTalkPlatformManagementTool.Setup
/// <summary>
/// Liest Registrywerte, Verknüpfungen und Uninstaller vor einer möglichen Mutation ein.
/// </summary>
/// <param name="log">Das Diagnoseprotokoll des aktuellen Setup-Laufs.</param>
/// <param name="warn">Die ausfallsichere Bedienerwarnung.</param>
/// <returns>Ein wiederherstellbarer Snapshot der Windows-Integration.</returns>
private WindowsIntegrationSnapshot CaptureWindowsIntegration()
private WindowsIntegrationSnapshot CaptureWindowsIntegration(SetupOperationLog log, Action<string> warn)
{
var snapshot = new WindowsIntegrationSnapshot
{
RegistryValues = new Dictionary<string, Tuple<object, RegistryValueKind>>(StringComparer.OrdinalIgnoreCase),
DesktopShortcut = ReadFileOrNull(DesktopShortcutPath),
StartMenuShortcut = ReadFileOrNull(StartMenuShortcutPath),
Uninstaller = ReadFileOrNull(UninstallerPath)
};
snapshot.DesktopShortcutCaptured = TryOptionalWindowsIntegrationStep(
"desktop_shortcut_snapshot",
"vorhandene Desktop-Verknuepfung fuer alle Benutzer sichern",
DesktopShortcutPath,
() => snapshot.DesktopShortcut = ReadFileOrNull(DesktopShortcutPath),
log,
warn);
using (var key = Registry.LocalMachine.OpenSubKey(UninstallKeyPath, false))
{
snapshot.RegistryKeyExisted = key != null;
@@ -581,7 +638,9 @@ namespace BizTalkPlatformManagementTool.Setup
/// Stellt einen zuvor erfassten Zustand der Windows-Integration wieder her.
/// </summary>
/// <param name="snapshot">Der wiederherzustellende Integrationszustand.</param>
private void RestoreWindowsIntegration(WindowsIntegrationSnapshot snapshot)
/// <param name="log">Das Diagnoseprotokoll des aktuellen Setup-Laufs.</param>
/// <param name="warn">Die ausfallsichere Bedienerwarnung.</param>
private void RestoreWindowsIntegration(WindowsIntegrationSnapshot snapshot, SetupOperationLog log, Action<string> warn)
{
if (snapshot == null) return;
Registry.LocalMachine.DeleteSubKeyTree(UninstallKeyPath, false);
@@ -596,9 +655,22 @@ namespace BizTalkPlatformManagementTool.Setup
}
}
}
RestoreFile(DesktopShortcutPath, snapshot.DesktopShortcut);
RestoreFile(StartMenuShortcutPath, snapshot.StartMenuShortcut);
RestoreFile(UninstallerPath, snapshot.Uninstaller);
if (snapshot.DesktopShortcutCaptured)
{
TryOptionalWindowsIntegrationStep(
"desktop_shortcut_rollback_restore",
"Desktop-Verknuepfung fuer alle Benutzer beim Rollback wiederherstellen",
DesktopShortcutPath,
() => RestoreFile(DesktopShortcutPath, snapshot.DesktopShortcut),
log,
warn);
}
else
{
log.Write("WARN", "event=optional_windows_integration_skipped role=desktop_shortcut_rollback_restore reason=snapshot_unavailable path=\"" + DesktopShortcutPath + "\"");
}
}
/// <summary>
@@ -786,11 +858,11 @@ namespace BizTalkPlatformManagementTool.Setup
/// <param name="targetExe">Der erwartete Zielpfad der Anwendung.</param>
/// <param name="desktopRequested">Der gewünschte Zustand der Desktop-Verknüpfung.</param>
/// <param name="log">Das Diagnoseprotokoll für die validierten Dateien.</param>
private void ValidateWindowsIntegration(string targetExe, bool desktopRequested, SetupOperationLog log)
/// <param name="warn">Die ausfallsichere Bedienerwarnung.</param>
/// <returns><c>true</c>, wenn auch der optionale Desktop-Zustand dem Wunsch entspricht.</returns>
private bool ValidateWindowsIntegration(string targetExe, bool desktopRequested, SetupOperationLog log, Action<string> warn)
{
if (!File.Exists(StartMenuShortcutPath)) throw new FileNotFoundException("Start menu shortcut was not created.", StartMenuShortcutPath);
if (desktopRequested != File.Exists(DesktopShortcutPath))
throw new InvalidOperationException("Desktop shortcut state does not match the setup selection. Requested=" + desktopRequested + ".");
if (!File.Exists(UninstallerPath)) throw new FileNotFoundException("Uninstaller was not installed.", UninstallerPath);
using (var key = Registry.LocalMachine.OpenSubKey(UninstallKeyPath, false))
@@ -805,8 +877,66 @@ namespace BizTalkPlatformManagementTool.Setup
log.WriteFileDetails("registered_uninstaller", UninstallerPath);
log.WriteFileDetails("start_menu_shortcut", StartMenuShortcutPath);
if (desktopRequested) log.WriteFileDetails("desktop_shortcut", DesktopShortcutPath);
log.Write("INFO", "event=windows_integration_validated registry_key=\"HKLM\\" + UninstallKeyPath + "\" desktop_shortcut=" + desktopRequested);
var desktopValidated = TryOptionalWindowsIntegrationStep(
"desktop_shortcut_validate",
"Desktop-Verknuepfung fuer alle Benutzer validieren",
DesktopShortcutPath,
() =>
{
var exists = File.Exists(DesktopShortcutPath);
if (desktopRequested != exists)
throw new InvalidOperationException("Desktop shortcut state does not match the setup selection. Requested=" + desktopRequested + ", exists=" + exists + ".");
if (exists) log.WriteFileDetails("desktop_shortcut", DesktopShortcutPath);
},
log,
warn);
log.Write("INFO", "event=windows_integration_validated registry_key=\"HKLM\\" + UninstallKeyPath
+ "\" desktop_shortcut_requested=" + desktopRequested
+ " desktop_shortcut_validated=" + desktopValidated);
return desktopValidated;
}
/// <summary>
/// Führt einen optionalen Windows-Integrationsschritt so aus, dass weder dessen Fehler
/// noch eine fehlerhafte Bedienerwarnung Installation, Rollback oder Deinstallation abbrechen.
/// </summary>
/// <param name="role">Die maschinenlesbare Rolle für das Diagnoselog.</param>
/// <param name="description">Die lesbare Beschreibung des optionalen Schritts.</param>
/// <param name="path">Der betroffene Pfad.</param>
/// <param name="operation">Die auszuführende optionale Operation.</param>
/// <param name="log">Das Diagnoseprotokoll des aktuellen Setup-Laufs.</param>
/// <param name="warn">Die optionale Bedienerwarnung.</param>
/// <returns><c>true</c> nach Erfolg, andernfalls <c>false</c>.</returns>
internal static bool TryOptionalWindowsIntegrationStep(
string role,
string description,
string path,
Action operation,
SetupOperationLog log,
Action<string> warn)
{
if (operation == null) throw new ArgumentNullException("operation");
try
{
operation();
log.Write("INFO", "event=optional_windows_integration_completed role=" + role + " path=\"" + path + "\"");
return true;
}
catch (Exception ex)
{
log.Write("WARN", "event=optional_windows_integration_warning role=" + role + " path=\"" + path + "\" " + SetupOperationLog.FormatException(ex));
var message = "WARNUNG: Optionaler Schritt '" + description + "' ist fehlgeschlagen: " + ex.Message
+ " Die Kernoperation wird fortgesetzt; Details stehen im Diagnoselog.";
try
{
if (warn != null) warn(message);
}
catch (Exception warningException)
{
log.Write("WARN", "event=optional_windows_integration_report_failed role=" + role + " " + SetupOperationLog.FormatException(warningException));
}
return false;
}
}
/// <summary>
@@ -65,7 +65,7 @@ namespace BizTalkPlatformManagementTool.Setup
{
AutoSize = true,
Font = new Font(Font.FontFamily, 14, FontStyle.Bold),
Text = "BizTalk Platform Management Tool 2.2.3"
Text = "BizTalk Platform Management Tool 2.2.4"
});
root.Controls.Add(new Label
{
@@ -74,8 +74,8 @@ namespace BizTalkPlatformManagementTool.Setup
Text = "Transaktionaler Installer mit SHA-256-Pruefung, Staging-Self-Test und automatischem Rollback.\r\nZiel: " + engine.InstallDirectory
});
desktopShortcut.Text = "Desktop-Verknuepfung fuer alle Benutzer erstellen";
desktopShortcut.Checked = true;
desktopShortcut.Text = "Optionale Desktop-Verknuepfung fuer alle Benutzer erstellen";
desktopShortcut.Checked = false;
desktopShortcut.AutoSize = true;
desktopShortcut.Enabled = !uninstallMode;
root.Controls.Add(desktopShortcut);
@@ -8,6 +8,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyProduct("BizTalk Platform Management Tool")]
[assembly: ComVisible(false)]
[assembly: Guid("675b68a9-bd80-46a5-b8c5-3b11b0b374e2")]
[assembly: AssemblyVersion("2.2.3.0")]
[assembly: AssemblyFileVersion("2.2.3.0")]
[assembly: AssemblyVersion("2.2.4.0")]
[assembly: AssemblyFileVersion("2.2.4.0")]
[assembly: InternalsVisibleTo("BizTalkPlatformManagementTool.Tests")]
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="2.2.3.0" name="BizTalkPlatformManagementTool.Setup" />
<assemblyIdentity version="2.2.4.0" name="BizTalkPlatformManagementTool.Setup" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security><requestedPrivileges><requestedExecutionLevel level="requireAdministrator" uiAccess="false" /></requestedPrivileges></security>
</trustInfo>
@@ -9,6 +9,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: ComVisible(false)]
[assembly: Guid("2c5b2c0a-f407-46c2-9e3b-1fa09fa8445a")]
[assembly: AssemblyVersion("2.2.3.0")]
[assembly: AssemblyFileVersion("2.2.3.0")]
[assembly: AssemblyVersion("2.2.4.0")]
[assembly: AssemblyFileVersion("2.2.4.0")]
[assembly: InternalsVisibleTo("BizTalkPlatformManagementTool.Tests")]
@@ -16,7 +16,7 @@ namespace BizTalkPlatformManagementTool.Services
/// <summary>
/// Current tool version written into generated snapshots.
/// </summary>
public const string Version = "2.2.3-net461";
public const string Version = "2.2.4-net461";
/// <summary>
/// Fallback application name used when WMI does not expose an application property.
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="2.2.3.0" name="BizTalkPlatformManagementTool" />
<assemblyIdentity version="2.2.4.0" name="BizTalkPlatformManagementTool" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>