using System; using System.Configuration; using System.Linq; using System.Text; using System.Windows.Forms; using MigrateConfiguration.Resources; using Installer.Common; using System.IO; using DTS.Common.Utilities; namespace MigrateConfiguration { internal static class ConfigurationMigration { /// /// Get the arguments from the MigrateConfiguration Installer Custom Action and migrates /// the config values from the most-recently installed version of DataPRO (if any). /// /// /// [TARGETDIR] /// [ProductVersion] /// private static void Main(string[] args) { var targetDir = string.Empty; var productVersion = new Version(); var noUI = string.Empty; string setupExeDir = string.Empty; for (var i = 0; i < args.Length; i++) { switch (i) { case 0: targetDir = args[i]; break; case 1: productVersion = new Version(args[i]); break; case 2: noUI = args[i]; break; case 3: setupExeDir = args[i]; break; } } try { if (!System.Diagnostics.EventLog.SourceExists("DataPROInstaller")) { System.Diagnostics.EventLog.CreateEventSource("DataPROInstaller", "DataPROInstallerLog"); } } catch { } var result = string.Empty; var allResults = new StringBuilder(); //try //{ // //Set the DownloadFolder setting to the current default which may be different than an old default // //before calling UpdateConfigurationIfPossible below, so that we don't stomp on a migrated value // //from the previous version which is not the old default. // var settingToFind = StringResources.DownloadFolder; // var valueToSet = StringResources.DataUpTwoLevels; // if (!ModifyConfigSetting(targetDir, StringResources.ApplicationSettings, StringResources.DataPROWin7PropertiesSettings, settingToFind, valueToSet, out result)) // { // allResults = CombineErrorResults(allResults, result); // allResults.Append("\r\n"); // allResults.Append(string.Format(StringResources.ThisSettingNeedsModification, settingToFind, valueToSet)); // allResults.Append("\r\n"); // } // //Set the ImportArchiveFolder setting so that it defaults to C:\DTS\DTS.Suite\ImportArchive (..\..\ImportArchive) // settingToFind = StringResources.ImportArchiveFolder; // valueToSet = StringResources.ImportArchiveUpTwoLevels; // if (!ModifyConfigSetting(targetDir, StringResources.ApplicationSettings, StringResources.DataPROWin7PropertiesSettings, settingToFind, valueToSet, out result)) // { // allResults = CombineErrorResults(allResults, result); // allResults.Append("\r\n"); // allResults.Append(string.Format(StringResources.ThisSettingNeedsModification, settingToFind, valueToSet)); // allResults.Append("\r\n"); // } //} //catch (Exception ex) //{ // allResults = CombineErrorResults(allResults, ex.Message); // allResults.Append("\r\n"); //} //Note that if the old DownloadFolder setting is the old default, we will not migrate it, //but instead we will use the current default setting that we set above. UpdateConfigurationIfPossible(targetDir, productVersion, setupExeDir, out result); allResults.Append(result); allResults.Append("\r\n"); //try //{ // if (!FixRunTimeModulesPath(targetDir, StringResources.DTSPlugins, out result)) // { // allResults = CombineErrorResults(allResults, result); // allResults.Append("\r\n"); // allResults.Append(StringResources.DTSPluginsNeedsModification); // allResults.Append("\r\n"); // } //} //catch (Exception ex) //{ // allResults = CombineErrorResults(allResults, ex.Message); // allResults.Append("\r\n"); //} if (string.IsNullOrWhiteSpace(allResults.ToString())) return; if (noUI != "TRUE") { MessageBox.Show(allResults.ToString(), StringResources.ConfigMigrationStatus, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); } } /// /// Get the most-recent previously installed config file and migrate any changed settings to the newly-installed config file /// /// The directory where the new config file resides. /// The version of DataPRO that was just installed. /// Text describing the success/failure of the config migration. public static void UpdateConfigurationIfPossible(string targetDir, Version installingVersion, string setupExeDir, out string result) { var log = new System.Diagnostics.EventLog(); log.Source = "MySource"; result = string.Empty; var subKey = PreviousInstall.GetMostRecentlyInstalledSubKeyName(installingVersion, out string nextLowerVersion); //log.WriteEntry("MostRecentlyInstalledSubKeyName = " + subKey); if (string.IsNullOrWhiteSpace(subKey)) return; var nextLowerPath = PreviousInstall.GetMostRecentlyInstalledPath(subKey); var allResults = new StringBuilder(); _ = MigrateLicenseFile(nextLowerVersion, nextLowerPath, targetDir, setupExeDir, out var migrateLicenseResult); allResults.AppendLine(migrateLicenseResult); if (allResults.ToString() != StringResources.ConfigDidNotNeedToBeUpdated) { //Both user and application values were successful, and at least some user values were updated so //be sure to return that information if no application values were updated. result = allResults.ToString(); } } private static StringBuilder CombineErrorResults(StringBuilder allResults, string result) { if (allResults.Length > 0) { allResults.Append("\r\n"); } allResults.Append(result); return allResults; } /// /// Migrates the UserSettings section of the config file /// /// The DataPRO version of the old config file. /// The path to the old config file. /// The path to the new config file. /// Text describing the success/failure of the config migration. /// True if migration succeeded or was not needed due to all defaults in the old config file, false if it failed. private static bool MigrateUserSettings(string nextLowerVersion, string nextLowerPath, string targetDir, out string result) { return MigrateSettings(StringResources.UserSettings, nextLowerVersion, nextLowerPath, targetDir, out result); } /// /// identifies if a file is a datapro license /// /// /// private static bool IsDataPROLicense(string path) { if (!File.Exists(path)) { return false; } var contents = File.ReadAllText(path); if (contents.Contains("") && contents.Contains("")) { return true; } return false; } /// /// finds any licenses in the directory or subdirectories /// /// /// private static string FindLicenseInPath(string path, int subDirectoriesToCheck) { if (string.IsNullOrWhiteSpace(path)) { return null; } if (!Directory.Exists(path)) { return null; } var files = new DirectoryInfo(path).GetFiles("*.lic"); foreach (var file in files) { if (IsDataPROLicense(file.FullName)) { return file.FullName; } } if (0 >= subDirectoriesToCheck) { return null; } subDirectoriesToCheck--; var directories = new DirectoryInfo(path).GetDirectories(); foreach (var dir in directories) { var file = FindLicenseInPath(dir.FullName, subDirectoriesToCheck); if (!string.IsNullOrWhiteSpace(file)) { return file; } } return null; } /// /// copies license file from old installation to a new installation /// /// next lowest version installed /// path to next lower version /// the directory of the new install /// displayable string indicating results /// true if license file was copied, false otherwise private static bool MigrateLicenseFile(string nextLowerVersion, string nextLowerPath, string targetDir, string setupExeDir, out string result) { try { var installVersionPath = FindLicenseInPath(new DirectoryInfo(setupExeDir).Parent.FullName, 2); if (null != installVersionPath && File.Exists(installVersionPath)) { var newPath = Path.Combine(targetDir, new FileInfo(installVersionPath).Name); File.Copy(installVersionPath, newPath); result = StringResources.InstallerLicenseFileFoundCopied; return true; } var oldVersionPath = FindLicenseInPath(nextLowerPath, 2); if (null != oldVersionPath && File.Exists(oldVersionPath)) { var newPath = Path.Combine(targetDir, new FileInfo(oldVersionPath).Name); File.Copy(oldVersionPath, newPath); result = StringResources.OldLicenseFoundCopied; return true; } result = StringResources.NoLicenseFound; return false; } catch (Exception ex) { result = $"{StringResources.FailedToCopyLicense} {ex.Message}"; return false; } } /// /// Migrates the ApplicationSettings section of the config file /// /// The DataPRO version of the old config file. /// The path to the old config file. /// The path to the new config file. /// Text describing the success/failure of the config migration. /// True if migration succeeded or was not needed due to all defaults in the old config file, false if it failed. private static bool MigrateAppSettings(string nextLowerVersion, string nextLowerPath, string targetDir, out string result) { return MigrateSettings(StringResources.ApplicationSettings, nextLowerVersion, nextLowerPath, targetDir, out result); } /// /// If the old config file contains an element in the new config file, and it is different, copy it to the new config file. /// /// Either UserSettings or ApplicationSettings. /// The DataPRO version of the old config file. /// The path to the old config file. /// The path to the new config file. /// Text describing the success/failure of the config migration. /// True if migration succeeded or was not needed due to all defaults in the old config file, false if it failed. private static bool MigrateSettings(string settingsType, string nextLowerVersion, string nextLowerPath, string targetDir, out string result) { var oldSettings = new SettingElementCollection(); if (!GetOldSettings(settingsType, nextLowerPath, out result, out oldSettings)) { return false; } else { var newSettings = new SettingElementCollection(); Configuration newConfig; if (!ConfigInitializationHelper.GetNewSettings(settingsType, targetDir, out result, out newSettings, out newConfig)) { return false; } else { SaveMigratedSettings(nextLowerVersion, oldSettings, newSettings, newConfig, out result); return true; } } } /// /// Gets the settings from the old config file /// /// Either UserSettings or ApplicationSettings. /// The path to the old config file. /// Text describing the success/failure of the config migration. /// The settings from the old config file /// True if the settings were successfully found and processed, false if not. private static bool GetOldSettings(string settingsType, string nextLowerPath, out string result, out SettingElementCollection oldSettings) { result = string.Empty; oldSettings = null; Configuration oldConfig; var oldPath = string.Empty; try { //Open the config file from the most-recently installed version of DataPRO - this assumes that it was installed in the default folder!!! oldPath = nextLowerPath + StringResources.RegistryDataPROExe; oldConfig = ConfigurationManager.OpenExeConfiguration(@oldPath); } catch (System.Exception ex) { result = string.Format(StringResources.OldSettingsCouldNotBeFound, ex.Message, oldPath); return false; } oldSettings = GetConfigSettings(settingsType, oldConfig); if (oldSettings != null) return true; result = StringResources.OldSettingsCouldNotBeProcessed; return false; } /// /// Update the new config file if needed /// /// The highest version installed that is lower than this version /// The settings from the old config file /// The settings from the new config file /// The config being modified /// Text describing the success/failure of the config migration. /// True if the settings were successfully found and processed, false if not. private static void SaveMigratedSettings(string nextLowerVersion, SettingElementCollection oldSettings, SettingElementCollection newSettings, Configuration newConfig, out string result) { var oldSettingsDictionary = oldSettings.Cast().ToDictionary(oldSetting => oldSetting.Name, oldSetting => oldSetting.Value.ValueXml.InnerXml); var settingsToBeMigrated = new SettingElementCollection(); foreach (System.Configuration.SettingElement newSetting in newSettings) { //If this setting exists in the old config, and it is different than the default that was installed, migrate the value if (oldSettingsDictionary.ContainsKey(newSetting.Name) && oldSettingsDictionary[newSetting.Name] != newSetting.Value.ValueXml.InnerXml) { //Only change from the new default DownloadFolder setting to the old DownloadFolder setting if it's not the previous default ("..\Data") if (newSetting.Name != StringResources.DownloadFolder || oldSettingsDictionary[StringResources.DownloadFolder] != StringResources.DataUpOneLevel) { //Add to the list of settings that need to be migrated settingsToBeMigrated.Add(newSetting); } } } foreach (System.Configuration.SettingElement settingToBeMigrated in settingsToBeMigrated) { //Migrate the changed value(s) newSettings.Remove(settingToBeMigrated); settingToBeMigrated.Value.ValueXml.InnerXml = oldSettingsDictionary[settingToBeMigrated.Name]; newSettings.Add(settingToBeMigrated); } newConfig.Save(); result = settingsToBeMigrated.Count <= 0 ? StringResources.ConfigDidNotNeedToBeUpdated : string.Format(StringResources.ConfigWasUpdated, nextLowerVersion); } /// /// This allows you to change a config setting. /// /// The path to the config file /// For example, "applicationSettings" /// For example, "DataPROWin7.Properties.Settings" /// For example, "DownloadFolder" /// For example, "..\..\Data" /// /// private static bool ModifyConfigSetting(string targetDir, string sectionGroupToFind, string sectionToFind, string settingToFind, string valueToSet, out string result) { result = string.Empty; try { //Open the new config file just installed var newPath = Path.Combine(targetDir, StringResources.RegistryDataPROExe); var newConfig = ConfigurationManager.OpenExeConfiguration(@newPath); var settingFound = false; var newConfigSectionGroup = newConfig.SectionGroups[sectionGroupToFind]; if (newConfigSectionGroup != null) { var applicationSettingsSection = (ClientSettingsSection)newConfigSectionGroup.Sections[sectionToFind]; var element = applicationSettingsSection.Settings.Get(settingToFind); if (null != element) { settingFound = true; applicationSettingsSection.Settings.Remove(element); element.Value.ValueXml.InnerXml = valueToSet; applicationSettingsSection.Settings.Add(element); newConfig.Save(); } } if (!settingFound) { result = string.Format(StringResources.SettingNotFound, settingToFind); return false; } } catch (Exception ex) { result = ex.Message; return false; } return true; } /// /// Gets the settings in a section group of the config file. /// /// Examples include "userSettings" and "applicationSettings" /// The config file to be interrogated. /// A collection of settings from the requested section of the config file. private static SettingElementCollection GetConfigSettings(string settingsType, Configuration config) { var clientSettingsSection = new ClientSettingsSection(); var configurationSectionGroup = config.SectionGroups[settingsType]; if ((configurationSectionGroup != null) && (configurationSectionGroup.Sections[0] != null)) { clientSettingsSection = configurationSectionGroup.Sections[0] as System.Configuration.ClientSettingsSection; } return clientSettingsSection?.Settings; } } }