using DTS.Common.Storage; using DTS.Common.Enums; using DBConfiguration.Properties; using Microsoft.Win32; using System.Diagnostics; using System; using System.Text; using System.Windows.Forms; using System.IO; using System.Configuration; namespace DBConfiguration { public class CommonUtilities { public CommonUtilities() { log.Source = "DataPRODbMigratorInstaller"; } private readonly EventLog log = new EventLog(); public void InitializeDbToTSRAIR(string targetDir) { var targetDbDir = $"{targetDir}\\{Settings.Default.LocalDbFolder}"; var scriptsDir = Path.Combine(targetDir, Settings.Default.ScriptsFolder); DbOperations.Connection.DBName = "DataPRO"; //This cannot be changed during TSR AIR Go installation UpdateTSRAIRAppSettings(targetDir); var resultString = Attach(targetDbDir, scriptsDir); DbOperations.Connection.Initialize(InitializationTypes.TSRAIR, targetDir); _ = Detach(DbOperations.Connection.DBName, targetDbDir, scriptsDir); MessageBox.Show(Settings.Default.TSRAIRGoInstallationCompletedSuccessfully, Settings.Default.InstallationStatus, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); } private void UpdateTSRAIRAppSettings(string targetDir) { try { if (!GetNewSettings(Settings.Default.ApplicationSettings, targetDir, out var result, out var settings, out var config)) { log.WriteEntry($"failed to updatetsrairappsetting {result}"); } var setting = settings.Get("LaunchTSRAIRGo"); settings.Remove(setting); setting.Value.ValueXml.InnerXml = "True"; settings.Add(setting); config.Save(ConfigurationSaveMode.Full); ConfigurationManager.RefreshSection("appSettings"); } catch (Exception ex) { log.WriteEntry($"Failed to update tsr air app settings {ex.Message}"); //nothing to do right now } } public bool GetNewSettings(string settingsType, string targetDir, out string result, out SettingElementCollection newSettings, out Configuration newConfig) { result = string.Empty; newSettings = null; newConfig = null; var newPath = string.Empty; try { //Open the new config file just installed newPath = Path.Combine(targetDir, Settings.Default.RegistryDataPROExe); newConfig = ConfigurationManager.OpenExeConfiguration(@newPath); } catch (Exception ex) { result = string.Format(Settings.Default.NewSettingsCouldNotBeFound, ex.Message, newPath); return false; } newSettings = GetConfigSettings(settingsType, newConfig); if (newSettings != null) return true; result = Settings.Default.NewSettingsCouldNotBeProcessed; return false; } 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 ClientSettingsSection; } return clientSettingsSection?.Settings; } public string Attach(string targetDbDir, string scriptsDir) { log.WriteEntry(Settings.Default.AttachingPrevLocalDb); SetMigrationStatus(Settings.Default.AttachingPrevLocalDb); var resultString = InstallDatabase(targetDbDir, DbOperations.Connection.DBName, scriptsDir); return resultString; } public string InstallDatabase(string dBdir, string dbName, string scriptsDir) { string resultString = ""; try { DbOperations._usingCentralizedDB = false; DbOperations._usingMSSQL = true; DbOperations.Connection.Server = Settings.Default.LocalDbDataPROInstance; DbOperations._usingNTLMAuthentication = true; resultString = ProcessSqlLocalDbCommand(Settings.Default.StopDataProInstance); if (resultString.Length != 0) { MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly); } resultString = ProcessSqlLocalDbCommand(Settings.Default.DeleteDataProInstance); if (resultString.Length != 0) { MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly); } resultString = ProcessSqlLocalDbCommand(Settings.Default.CreateDataProInstance); if (resultString.Length != 0) { MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly); } resultString = ProcessSqlLocalDbCommand(Settings.Default.StartDataProInstance); if (resultString.Length != 0) { MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly); } Console.WriteLine("Attaching DataPRO"); //Attach the DataPRO database var dbFileName = Path.Combine(dBdir, dbName) + Settings.Default.Mdf; var logFileName = Path.Combine(dBdir, dbName) + Settings.Default.LogLdf; Console.WriteLine($"dbFileName is {dbFileName}"); Console.WriteLine($"logFileName is {logFileName}"); Console.WriteLine($"_scriptsDir is {scriptsDir}"); resultString = AttachOrDetachDatabase(scriptsDir, dbName, dbFileName, logFileName, Settings.Default.AttachDBsbat); if (resultString.Length != 0) { MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly); } Console.WriteLine("Attaching ISO"); //Attach the ISO database dbFileName = Path.Combine(dBdir, Settings.Default.ISO) + Settings.Default.Mdf; logFileName = Path.Combine(dBdir, Settings.Default.ISO) + Settings.Default.LogLdf; resultString = AttachOrDetachDatabase(scriptsDir, Settings.Default.ISO, dbFileName, logFileName, Settings.Default.AttachDBsbat); if (resultString.Length != 0) { MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly); } } catch (Exception ex) { log.WriteEntry($"Exception while getting previous local database version: {ex.Message}; Stacktrace: {ex.StackTrace}"); throw; } return resultString; } public string Detach(string sourceDbName, string targetDbDir, string scriptsDir) { //Detach the databases log.WriteEntry(string.Format(Settings.Default.DetachingLocalMigratedDb, sourceDbName)); SetMigrationStatus(string.Format(Settings.Default.DetachingLocalMigratedDb, sourceDbName)); var dbFileName = Path.Combine(targetDbDir, sourceDbName + Settings.Default.Mdf); var logFileName = Path.Combine(targetDbDir, sourceDbName + Settings.Default.LogLdf); var resultString = CommonUtilities.AttachOrDetachDatabase(scriptsDir, sourceDbName, dbFileName, logFileName, Settings.Default.DetachDBsbat); if (resultString.Length != 0) { MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly); } log.WriteEntry(Settings.Default.DetachingLocalISODb); SetMigrationStatus(Settings.Default.DetachingLocalISODb); dbFileName = Path.Combine(targetDbDir, Settings.Default.ISO + Settings.Default.Mdf); logFileName = Path.Combine(targetDbDir, Settings.Default.ISO + Settings.Default.LogLdf); resultString = CommonUtilities.AttachOrDetachDatabase(scriptsDir, Settings.Default.ISO, dbFileName, logFileName, Settings.Default.DetachDBsbat); return resultString; } public MigrationStatus SetMigrationStatus(string migrationStatus, bool output = false) { //Remove the previous status SetStatus(string.Empty); var migrationStatusClass = new MigrationStatus(); migrationStatusClass.StatusType = MigrationStatus.StatusTypes.MigrationStatus; migrationStatusClass.StatusText = migrationStatus; if (output) { Console.WriteLine(migrationStatus); } return migrationStatusClass; } private void SetStatus(string status, bool output = false) { var migrationStatusClass = new MigrationStatus(); migrationStatusClass.StatusType = MigrationStatus.StatusTypes.Status; migrationStatusClass.StatusText = status; if (output) { Console.WriteLine(status); } } /// /// Get the path to the latest version of SQL Server Express LocalDB /// installed, and run the command passed in. /// /// /// public string ProcessSqlLocalDbCommand(string command) { //SQL Server Express LocalDB 2014 is a Prerequisite of the DataPRO Installer, //so it should be there unless it has been subsequently uninstalled. var localDbPath = GetSqlServerLocalDBPath(); if (localDbPath == string.Empty) { log.WriteEntry($"localDbPath is empty"); //SQL Server LocalDb is not installed so display error and go away return Settings.Default.SqlServerLocalDbNotInstalled; } var sqlLocalDbExeFileName = localDbPath + Settings.Default.SqlLocalDBExe; log.WriteEntry($"sqlLocalDbExeFileName = {sqlLocalDbExeFileName}"); return SqlCommandProcessor(sqlLocalDbExeFileName, command); } public static string AttachOrDetachDatabase(string scriptsDir, string dbName, string sqlDbFileName, string sqlLogFileName, string attachOrDetach) { const string SqlCmdExe = "sqlcmd.exe"; var oDBCToolsPath = DTS.Common.Utils.Database.GetODBCToolsPath(null); var fullSqlcmdPath = Path.Combine(oDBCToolsPath, SqlCmdExe); //e.g. $"\"C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\110\\Tools\\Binn\\sqlcmd.exe\"" var batchFileName = Path.Combine(scriptsDir, attachOrDetach); return BatchCommandProcessor(batchFileName, dbName, sqlDbFileName, sqlLogFileName, fullSqlcmdPath); } private string GetSqlServerLocalDBPath() { var highestVersionInstalledPath = string.Empty; var rk = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); var sk1 = rk.OpenSubKey(Settings.Default.RegistrySoftwareMicrosoftMicrosoftSQLServerLocalDBInstalledVersions); if (sk1 == null) { log.WriteEntry($"sk1 is null; returning string.Empty"); return string.Empty; } var maxProductVersion = 0.0; foreach (var productSubKeyName in sk1.GetSubKeyNames()) { log.WriteEntry($"productSubKeyName is {productSubKeyName}"); var thisVersion = -1D; if (!double.TryParse(productSubKeyName, System.Globalization.NumberStyles.Float | System.Globalization.NumberStyles.AllowThousands, System.Globalization.CultureInfo.InvariantCulture, out thisVersion)) continue; log.WriteEntry($"thisVersion is {thisVersion}/maxProductVersion is {maxProductVersion}"); if (thisVersion < maxProductVersion) continue; maxProductVersion = thisVersion; var newKey = sk1.OpenSubKey(productSubKeyName); if (newKey == null) { log.WriteEntry($"newKey is null (productSubKeyName is {productSubKeyName}); continuing"); continue; } var val = newKey.GetValue(Settings.Default.InstanceAPIPath, -1, RegistryValueOptions.None).ToString(); log.WriteEntry($"val is {val}"); if ((val == "-1") || (!val.EndsWith(Settings.Default.SqlUserInstanceDll))) continue; log.WriteEntry($"highestVersionInstalledPath = {highestVersionInstalledPath}"); highestVersionInstalledPath = val.Substring(0, val.Length - Settings.Default.SqlUserInstanceDll.Length); } log.WriteEntry($"Returning {highestVersionInstalledPath.Replace(Settings.Default.LocalDB, Settings.Default.Tools)}"); return highestVersionInstalledPath.Replace(Settings.Default.LocalDB, Settings.Default.Tools); } public static StringBuilder sb = new StringBuilder(); public static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { if (outLine.Data != null) { if (string.IsNullOrWhiteSpace(outLine.Data)) { sb.Append(Environment.NewLine); } sb.Append(outLine.Data); } } public static string SqlCommandProcessor(string sqlLocalDbExeFileName, string command) { var resultString = string.Empty; sb.Clear(); var process = new Process { StartInfo = { FileName = sqlLocalDbExeFileName, Arguments = command, LoadUserProfile = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true } }; //* Set ONLY ONE handler here. process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); //* Start process process.Start(); //* Read one element asynchronously process.BeginErrorReadLine(); //* Read the other one synchronously var output = process.StandardOutput.ReadToEnd(); Console.WriteLine(output); process.WaitForExit(); if (sb.Length > 0) { resultString = sb.ToString(); } return resultString; } public static string BatchCommandProcessor(string batchFileName, string dbName, string sqlDbFileName, string sqlLogFileName, string fullSqlcmdPath) { var resultString = string.Empty; sb.Clear(); var process = new Process { StartInfo = { FileName = batchFileName, Arguments = dbName + " " + "\"" + sqlDbFileName + "\"" + " " + "\"" + sqlLogFileName + "\"" + " " + "\"" + fullSqlcmdPath + "\"", LoadUserProfile = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true } }; //* Set ONLY ONE handler here. process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); //* Start process process.Start(); //* Read one element asynchronously process.BeginErrorReadLine(); //* Read the other one synchronously var output = process.StandardOutput.ReadToEnd(); Console.WriteLine(output); process.WaitForExit(); if (sb.Length > 0) { resultString = sb.ToString(); } return resultString; } } }