// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Data; using Microsoft.Web.Administration; // Add new host email stuff !!!!!!!!!!!!!!!!! // MasterHostId ??? does what ??? namespace Spludlow { public class Setup { // The last thing in the SETUP.txt file is AcceptConfiguration change this to “YES”. // All setup code is in this class, it's not very elegent but it should be pretty clear what's going off. // !!!! manually setting firsthost on node sort with 2 mothds !!!!!!!!!!!!!!! private static string SetupFilename = @"SETUP.txt"; private static int VersionNumber = 1; public static void MakeFileMaster() { MakeFile(true); } public static void MakeFileNode() { MakeFile(false); } public static void MakeFile(bool firstHost) { MakeFile("SpludlowV" + VersionNumber, firstHost); } public static void MakeFile(string frameworkNamespace, bool firstHost) { int portNumberBase = 32000 + (VersionNumber % 10) * 100; MakeFile(frameworkNamespace, portNumberBase, firstHost); } public static void MakeFile(string frameworkNamespace, int portNumberBase, bool firstHost) { bool overwrite = true; //bool firstHost = true; int passwordLength = 64; int intranetSuffixLength = 4; int webServiceSuffixLength = 16; string applicationPoolSuffix = "V" + VersionNumber; // !!! rename to vNumber string workgroup = Spludlow.ManagementObjects.SystemWorkgroup(); string domain = Spludlow.ManagementObjects.SystemDomain(); string localhostOrDomain = domain; if (localhostOrDomain == null) localhostOrDomain = Environment.MachineName; string securityGroup = localhostOrDomain + @"\SpludlowGroup"; string spludlowUser = localhostOrDomain + @"\SpludlowUser"; string spludlowAdminUser = localhostOrDomain + @"\SpludlowAdmin"; string databaseSource = Environment.MachineName; string databaseAdmin = "Data Source=" + databaseSource + ";Integrated Security=True;"; string database = databaseAdmin + "Initial Catalog=" + frameworkNamespace + ";"; string[] file = new string[] { "# Welcome to the Spludlow SETUP.txt file. This file must be editied before installation can procede. The file is only required during installation, although you should keep a copy.", "", "# The line format is: 'KEY<-Any number on tabs->VALUE'. DO NOT change any KEYs. DO NOT use tabs in values. Lines that start with '#' are ignored. Whitespace is trimmed from both ends of each line.", "", "# You need to go through this file and check every value to suit your requirments.", "", "# REMEMBER to save this file when you have made changes!", "", "# All initial values have been either best guessed, defaults used, or a reasonable example provided.", "# Having said if you want to get testing the framework mega quickly you can run the file as is provided setup is creating the users and the database is local using Windows Authentication.", "", "# Passwords have been randomally generated. If you have existing users setup the credentials in this file need replacing to match the existing users.", "# If you don't have existing users setup then you can use the random passwords in this file to create the users.", "", "# This setup directory (with this file in it) can be removed after installation.", "", "# Passwords are only used for installing Service Processes and Web Services, they are not stored by the framework.", "", "# If you are having trouble deleting the setup directory, then check notepad, explorer windows, and the command promt are not in the diectory, or have anything withing the directory open.", "", "", "# If you change this to True then any existing framework componets are removed and then reinstalled during setup. This includes the Config directory and the database, among others !!! Make sure you have what you need before overwriting anything.", "OverWrite " + overwrite.ToString(), "", "# Should be 'Ture' for installing the first host otherwise 'False'.", "FirstHost " + firstHost.ToString(), "", "########################### Credentials ###########################", "", "# These are important. If you are using setup to create the users (first time using domain users or every host using local users) setup will look here", "# When Setup installs the Web Application Pools and Service Process it will get the credentials from here", "# With domain users you want to copy the credentials from the first SETUP.txt file to any aditional node host's SETUP.txt files, all 5 entries are identical in a domain.", "# With local users (workgroup) you need to make sure the Spludlow User password 'SpludlowUserPass' is the same on each host on a network (if you want hosts to share resources like fileshares) so copy the password from the Master host's SETUP.txt", "# The Admin User Password 'SpludlowAdminUserPass' can be unique to each host.", "# All usernames need to be in the format 'DOMAIN\\UserName' or 'LOCALHOST\\UserName'", "", "# Windows Identity used when assigning permissions to local resources; directories and message queues.", "SecurityGroup " + securityGroup, "", "# The User used to run Service Process and Web Service.", "SpludlowUser " + spludlowUser, "SpludlowUserPass " + Spludlow.RandomKeys.Password(passwordLength), "", "# The User used to run the Admin Web Service.", "SpludlowAdminUser " + spludlowAdminUser, "SpludlowAdminUserPass " + Spludlow.RandomKeys.Password(passwordLength), "", "########################### Web Paths ###########################", "", "# Aliases (Paths) to web applications, used by setup when adding the applications to IIS. random characters appended for security.", "# The 2 WebService paths here are required by the Intranet when adding further hosts, you can copy and paste them from here.", "Spludlow-WebService-Admin " + "Spludlow-WebService-Admin" + applicationPoolSuffix + "-" + Spludlow.RandomKeys.AlphaNumeric(webServiceSuffixLength), "Spludlow-WebService " + "Spludlow-WebService" + applicationPoolSuffix + "-" + Spludlow.RandomKeys.AlphaNumeric(webServiceSuffixLength), "Spludlow-Intranet " + "Spludlow-Intranet" + applicationPoolSuffix + "-" + Spludlow.RandomKeys.AlphaNumeric(intranetSuffixLength), "", "# MachineName:" + Environment.MachineName, "", "########################### Advanced ###########################", "", "# Don't touch any of these unless you have a pretty good reason.", "", "# Prefixed to all queue names to give physical queue names", "QueueNamespace " + frameworkNamespace, "", "", "# Web Application Pool Suffix, put om the end of application Ids to give the Application Pool Name.", "ApplicationPoolSuffix " + applicationPoolSuffix, "", "", "# Name of the Windows Service Process. This must match the name on the Installer within the service project. If you want to change it you must also change it in the project and recompile.", "ServiceProcessName " + "Spludlow-Service" + applicationPoolSuffix, "", "", "# The deafult port number start is 32v00 (where v is the last digit on the version number). Spludlow-Service.exe will run on this port number.", "PortNumberStart " + portNumberBase, "", "", "ProgramFiles " + @"C:\Program Files\" + frameworkNamespace, "ProgramFilesAdmin " + @"C:\Program Files\" + frameworkNamespace + " Admin", "ProgramData " + @"C:\ProgramData\" + frameworkNamespace, "", "", "################### Master install only below here, ignore rest for a node installation #########", "", "########################### Database ###########################", "", "# Only needed on the first host change these connection strings to match your enviroment", "", "# Database Name used. If setting up a test host on the same network as live hosts, sharing the same database server, you may want to change to something like 'SpludlowV1TEST'", "DatabaseName " + frameworkNamespace, "", "# Database Connection String used when creating and droping (if replacing) the Spludlow database. This connection should have sysadmin rights during installation.", "# If no tables exist in the databse then setup will create all tables. If tables already exist then the relevent* tables will have all records deleted.", "# If you don't want to (re)create the database you can comment out this line and setup will not try. Your database administrator may have created an empty database for you with permissions only for that database.", "DatabaseConnectionAdmin " + databaseAdmin, "", "# DatabaseConnection String used for normal operation, should have at least read and write permission to the Spludlow database's tables", "DatabaseConnection " + database, "", "# Database Login. If using Windows authentication, using local WORKGROUP users, and database server is on another computer then change the host part of this to the databse server host name", "DatabaseLogin " + securityGroup, "", "# Random sa password if you need it:" + Spludlow.RandomKeys.Password(passwordLength), "", "########################### Organization ###########################", "", "# Only required by the Master (First) host, all this stuff is entered through the Intranet when adding further node hosts.", "", "# Short ID of first Organization used by the framework's configuration. Shortened business name is a good option. May want to setup a test system with name like 'MyCompTEST'", "OrganizationId " + "MyComp", "", "", "# Short ID of first network used by the framework's configuration. Good to keep OrganizationId in there followed by network name. 'Head' representing head office, may use; shortended area e.g. 'Notts' or usage based e.g. 'Desp' for despatch", "NetworkId " + "MyComp-Head", "", "", "# Pubic address of host's root web. You can ignore this for now. Until you start running hosts on other networks it don't do anything.", "PublicWebAddress " + "https://headOffice.myComp.net/", "", "", "# The networks SMTP server for sending mail", "NetworkSmtpServer " + Environment.MachineName, "", "", "# Email addresses used when sending system mail", "MailToAddress " + "@myComp.co.uk", "MailFromAddress " + "spludlow@myComp.net", "", "", "# EOF", }; File.WriteAllLines(SetupFilename, file); Console.WriteLine("Initial SETUP.txt file generated: " + SetupFilename); if (firstHost == false) { string configFilename = @"Spludlow.config"; //Current dir if (File.Exists(configFilename) == true) File.Delete(configFilename); File.WriteAllText(configFilename, ""); Console.WriteLine("Empty Spludlow.config file saved, please copy and paste the new contents from the Intranet Config.aspx page"); } } public static void UsersAndGroups() { Dictionary setupFile = ReadFile(SetupFilename); string localAdminGroup = Environment.MachineName + @"\Administrators"; string securityGroup = setupFile["SecurityGroup"]; string userName = setupFile["SpludlowUser"]; string password = setupFile["SpludlowUserPass"]; string userNameAdmin = setupFile["SpludlowAdminUser"]; string passwordAdmin = setupFile["SpludlowAdminUserPass"]; string[] checkAccounts = new string[] { localAdminGroup, securityGroup, userName, userNameAdmin }; foreach (string user in checkAccounts) { Spludlow.DirectoryService.IsDomain(user); } if (Spludlow.DirectoryService.Exists(securityGroup) == true) Console.WriteLine("UsersAndGroups; Security Group Already exists: " + securityGroup); else Spludlow.DirectoryService.AddGroup(securityGroup); if (Spludlow.DirectoryService.Exists(userName) == true) Console.WriteLine("UsersAndGroups; Spludlow User Already Exists: " + userName); else Spludlow.DirectoryService.AddUser(userName, password, securityGroup); if (Spludlow.DirectoryService.Exists(userNameAdmin) == true) Console.WriteLine("UsersAndGroups; Spludlow Admin User Already Exists: " + userNameAdmin); else Spludlow.DirectoryService.AddUser(userNameAdmin, passwordAdmin, new string[] { securityGroup, localAdminGroup }); if (Spludlow.DirectoryService.IsUserInGroup(userNameAdmin, localAdminGroup) == true) Console.WriteLine("UsersAndGroups; Spludlow Admin User Already In Local Administrators group: " + userNameAdmin); else Spludlow.DirectoryService.AddUserToGroup(userNameAdmin, localAdminGroup); } public static void LocalUsersAndGroups() // Create databse users where the host name part of the user will be repalced with local MachineName { Dictionary setupFile = ReadFile(SetupFilename); string securityGroup = setupFile["SecurityGroup"]; string userName = setupFile["SpludlowUser"]; string password = setupFile["SpludlowUserPass"]; int index; index = userName.IndexOf("\\"); userName = Environment.MachineName + userName.Substring(index); index = securityGroup.IndexOf("\\"); securityGroup = Environment.MachineName + securityGroup.Substring(index); string[] checkAccounts = new string[] { securityGroup, userName }; foreach (string user in checkAccounts) { Spludlow.DirectoryService.IsDomain(user); } if (Spludlow.DirectoryService.Exists(securityGroup) == true) Console.WriteLine("LocalUsersAndGroups; Security Group Already exists: " + securityGroup); else Spludlow.DirectoryService.AddGroup(securityGroup); if (Spludlow.DirectoryService.Exists(userName) == true) Console.WriteLine("LocalUsersAndGroups; Spludlow User Already Exists: " + userName); else Spludlow.DirectoryService.AddUser(userName, password, securityGroup); } public static void DatabaseLogin() { DatabaseLogin(false); } public static void DatabaseLogin(bool administrator) { Dictionary setupFile = ReadFile(SetupFilename); // If not domain or database not on this machine, need to: // Add user and group on databse machine // Add SpludlowUser with same password // Add SpludlowGroup // Add SpludlowUser to SpludlowGroup // name group as "DB" not "APP" when creating login (can use no domain?) // Domain or local database will work fixed !!!! string loginName = setupFile["DatabaseLogin"]; string adminKey = "DatabaseConnectionAdmin"; if (setupFile.ContainsKey(adminKey) == false) throw new ApplicationException("DatabaseLogin; DatabaseConnectionAdmin required in SETUP.txt"); string databaseConnectionAdmin = setupFile[adminKey]; Spludlow.Data.IDAL dal = Spludlow.Data.DAL.Create(databaseConnectionAdmin); dal.LoginCreate(loginName, administrator); // will thow if exists !!!! dont matter as called on its own Console.WriteLine("DatabaseLogin; Database login created: " + loginName + ", administrator=" + administrator); } public static void InstallMaster() { Remove(true); DirectoryProgramFiles(false); DirectoryProgramData(false); MessageQueues(false); Database(false); DatabaseInsert(); ConfigApplicationsFiles(); ConfigFile(); WebServiceApplicationPools(false); WebApplications(false); ServiceProcess(false); Dictionary setupFile = ReadFile(SetupFilename); string intranet = "https://" + Environment.MachineName.ToLower() + "/" + setupFile["Spludlow-Intranet"] + "/"; Console.WriteLine("#################"); Console.WriteLine(" Master Install Complete! Please browse to the Intranet and switch on the Service Process."); Console.WriteLine(intranet); Console.WriteLine("##################"); } public static void RemoveMaster() { Remove(true); } public static void InstallNode() { string configFilename = "Spludlow.config"; // Current Directory if (File.Exists(configFilename) == false || Spludlow.Io.Files.FileLength(configFilename) == 0) throw new ApplicationException(configFilename + " missing or empty, please create it on the Intranet then copy to the setup directory."); Remove(false); DirectoryProgramFiles(false); DirectoryProgramData(false); MessageQueues(false); ConfigApplicationsFiles(); CopyConfigFile(configFilename); WebServiceApplicationPools(false); WebApplications(false); ServiceProcess(false); Console.WriteLine("#################"); Console.WriteLine(" Node Install Complete! Please browse to the Intranet on the Master and switch on the Service Process on this host."); Console.WriteLine("##################"); } public static void RemoveNode() { Remove(false); } public static void Remove(bool master) { ServiceProcess(true); WebApplications(true); WebServiceApplicationPools(true); if (master == true) Database(true); MessageQueues(true); DirectoryProgramData(true); DirectoryProgramFiles(true); } public static void DirectoryProgramFiles(bool uninstall) { Dictionary setupFile = ReadFile(SetupFilename); bool overWrite = Boolean.Parse(setupFile["OverWrite"]); bool firstHost = Boolean.Parse(setupFile["FirstHost"]); string programFiles = setupFile["ProgramFiles"]; string programFilesAdmin = setupFile["ProgramFilesAdmin"]; Dictionary appProgDirs = ApplicationProgramDirectories(); string securityGroup = setupFile["SecurityGroup"]; if (overWrite == false && (Directory.Exists(programFiles) == true || Directory.Exists(programFilesAdmin) == true)) throw new ApplicationException("OverWrite is not set to True and ProgramFiles or ProgramFilesAdmin directories exist."); string[] dirs = new string[] { programFiles, programFilesAdmin }; foreach (string dir in dirs) { if (Directory.Exists(dir) == true) { Directory.Delete(dir, true); Console.WriteLine("DirectoryProgramFiles; Existing Program Files Directory Deleted: " + dir); } } if (uninstall == true) return; foreach (string dir in dirs) { Directory.CreateDirectory(dir); Console.WriteLine("DirectoryProgramFiles; New Program Files Directory Created: " + dir); } Spludlow.Io.Dirs.AddSecurityFullControl(programFiles, securityGroup); List applicationIds = new List(new string[] { "Spludlow-Process", "Spludlow-Service", "Spludlow-WebService", "Spludlow-WebService-Admin" }); if (firstHost == true) applicationIds.Add("Spludlow-Intranet"); string programData = setupFile["ProgramData"]; //string sourceDirectory = "ProgramFiles"; // in current Dir ! foreach (string applicationId in applicationIds) { string sourceAppDirectory = applicationId; // sourceDirectory + @"\" + applicationId; if (Directory.Exists(sourceAppDirectory) == false) throw new ApplicationException("Source Application Directory not found: " + sourceAppDirectory); string targetDirectory = appProgDirs[applicationId]; Spludlow.Io.Dirs.Copy(sourceAppDirectory, targetDirectory); FixConfigPath(applicationId, targetDirectory, programData); } Console.WriteLine("Setup; Program Files Directory Ready."); } private static void FixConfigPath(string applicationId, string programDirectory, string programDataDirectory) // Also do in release !!!!!!!!!!!!!! { string configFilename = programDirectory + @"\Web.config"; if (File.Exists(configFilename) == false) configFilename = programDirectory + @"\" + applicationId + ".exe.config"; if (File.Exists(configFilename) == false) throw new ApplicationException("FixConfigPath; Could not find application config in either 'Web.config' or: " + configFilename); StringBuilder result = new StringBuilder(); foreach (string line in File.ReadAllLines(configFilename)) { if (line.Trim().StartsWith(" ApplicationProgramDirectories() { Dictionary setupFile = ReadFile(SetupFilename); string programFiles = setupFile["ProgramFiles"]; string programFilesAdmin = setupFile["ProgramFilesAdmin"]; Dictionary result = new Dictionary(); foreach (string applicationId in AllApplicationIds) { string programDiectory = programFiles; if (applicationId == "Spludlow-WebService-Admin") programDiectory = programFilesAdmin; string targetAppDirectory = programDiectory + @"\" + applicationId; result.Add(applicationId, targetAppDirectory); } return result; } public static void DirectoryProgramData(bool uninstall) { Dictionary setupFile = ReadFile(SetupFilename); string timeStamp = Spludlow.Text.TimeStamp(); bool overWrite = Boolean.Parse(setupFile["OverWrite"]); string programData = setupFile["ProgramData"]; string securityGroup = setupFile["SecurityGroup"]; if (overWrite == false && Directory.Exists(programData) == true) throw new ApplicationException("OverWrite is not set to True and the programData directory exists."); if (Directory.Exists(programData) == true) { string copyDir = programData + "." + timeStamp; Directory.Move(programData, copyDir); Console.WriteLine("DirectoryProgramData; Existing Program Data Moved to safty: " + copyDir); } if (uninstall == true) return; Directory.CreateDirectory(programData); Console.WriteLine("DirectoryProgramData; New Program Data Directory Created: " + programData); Spludlow.Io.Dirs.AddSecurityFullControl(programData, securityGroup); string[] dirs = new string[] { @"Config", @"Config\Credentials", @"Data", @"Logs", @"Logs\Print", @"Release", @"Release\New", @"Release\Backup", @"Release\Binaries", @"Temp", }; foreach (string dir in dirs) Directory.CreateDirectory(programData + @"\" + dir); string sourceDirectory = @"ProgramData\Data"; // in current Dir ! string targetDirectory = setupFile["ProgramData"] + @"\Data"; foreach (string filename in Directory.GetFiles(sourceDirectory)) { File.Copy(filename, targetDirectory + @"\" + Path.GetFileName(filename)); } Console.WriteLine("DirectoryProgramData; Finished."); } public static void MessageQueues(bool uninstall) { Dictionary setupFile = ReadFile(SetupFilename); bool overWrite = Boolean.Parse(setupFile["OverWrite"]); bool firstHost = Boolean.Parse(setupFile["FirstHost"]); string queueNamespace = setupFile["QueueNamespace"]; string spludlowUser = setupFile["SpludlowUser"]; List queueNames = new List(new string[] { "Sys", "Run" }); if (firstHost == true) queueNames.Add("Log"); foreach (string queueName in queueNames) { string name = queueNamespace + "." + queueName; if (Spludlow.MessageQueues.Exists(queueNamespace, queueName) == true) { if (overWrite == false) throw new ApplicationException("OverWrite is not set to True and the message queue exists: " + queueNamespace + "." + queueName); Spludlow.MessageQueues.DeleteQueue(queueNamespace, queueName); Console.WriteLine("MessageQueues; Existing Queue deleted: " + name); } if (uninstall == false) { Spludlow.MessageQueues.Create(queueNamespace, queueName, spludlowUser); Console.WriteLine("MessageQueues; New Queue created: " + name); } } Console.WriteLine("MessageQueues; Finished."); } // "C:\Program Files\SpludlowV1\Spludlow-Process\Spludlow-Process.exe" Spludlow Spludlow.Setup MessageQueuesRouting "SPLUDLOW\SpludlowUser" // "C:\Program Files\SpludlowV1\Spludlow-Process\Spludlow-Process.exe" Spludlow Spludlow.MessageQueues Create "SpludlowV1" "Log" "SPLUDLOW\SpludlowUser" // Must also add to Spludlow-Service.txt !!!! public static void MessageQueuesRouting(string spludlowUser) // Only on exiting systems run from command prompt as admin !!!!!! { string routerHost = Spludlow.Config.Get("Spludlow.Host.Router"); string queueNamespace = Spludlow.Config.Get("Spludlow.QueueNamespace"); string networkId = Spludlow.Config.Get("Spludlow.NetworkId"); string[] networkIds = Spludlow.Text.Split(Spludlow.Config.Get("Spludlow.Networks"), ',', true, false); try { Spludlow.Log.Address = null; // Switch off queue logging botch foreach (string remoteNetworkId in networkIds) { string queueName = "Route." + remoteNetworkId; bool queueExists = Spludlow.MessageQueues.Exists(queueNamespace, queueName); // If router and remote network if (routerHost == Environment.MachineName && remoteNetworkId != networkId) { if (queueExists == true) { Spludlow.Log.Info("MessageQueuesRouting, Routing message queue already exists: " + queueName); } else { Spludlow.MessageQueues.Create(queueNamespace, queueName, spludlowUser); Spludlow.Log.Report("MessageQueuesRouting, Routing message queue created: " + queueName); } } else { if (queueExists == true) Spludlow.Log.Warning("MessageQueuesRouting, Usless routing message queue: " + queueName); } } } finally { Spludlow.Log.SetAddress(); } } public static void Database(bool uninstall) { Dictionary setupFile = ReadFile(SetupFilename); bool overWrite = Boolean.Parse(setupFile["OverWrite"]); string databaseName = setupFile["DatabaseName"]; string adminKey = "DatabaseConnectionAdmin"; DataSet schema = new DataSet(); if (uninstall == false) schema = Spludlow.Data.Schemas.ReadDirectory(@"Schema"); if (setupFile.ContainsKey(adminKey) == true) // Have database create/delete permission { string databaseConnectionAdmin = setupFile[adminKey]; Spludlow.Data.IDAL dalAdmin = Spludlow.Data.DAL.Create(databaseConnectionAdmin); if (dalAdmin.DatabaseExists(databaseName) == true) { if (overWrite == false) throw new ApplicationException("Database; Already exists and OverWrite is False: " + databaseName); Console.WriteLine("Database; Allready exists: " + databaseName); dalAdmin.DatabaseDelete(databaseName); Console.WriteLine("Database; Deleted existing: " + databaseName); } if (uninstall == false) { dalAdmin.DatabaseCreate(databaseName, schema); Console.WriteLine("Database; Created new: " + databaseName); Console.WriteLine("Database; Tables created: " + databaseName); } } if (uninstall == true) return; string databaseConnection = setupFile["DatabaseConnection"]; string[] tableNames = Spludlow.Data.Schemas.TableNamesInOrder(schema); Spludlow.Data.IDAL dal = Spludlow.Data.DAL.Create(databaseConnection); if (dal.TableList().Length == 0) { foreach (string tableName in tableNames) dal.TableCreate(tableName, schema); Console.WriteLine("Database; Tables created: " + databaseName); } else { if (overWrite == false) throw new ApplicationException("Database; Tables already exist and OverWrite is False: " + databaseName); for (int index = tableNames.Length - 1; index >= 0; --index) { string tableName = tableNames[index]; int recs = dal.ExecuteNonQuery("DELETE FROM " + tableName); Console.WriteLine("Database; Table all rows deleted: " + databaseName + ", " + tableName + ", count: " + recs); } } try { DatabaseUser(); } catch (Exception ee) { Console.WriteLine("Database; WARNING!!! Failed to create Standard Database User, please manually create: " + ee.Message); } } public static void DatabaseUser() { DatabaseUser(false); } public static void DatabaseUser(bool administrator) { // for remote workgroup need to user host on remote !!! // Works on local or domain Dictionary setupFile = ReadFile(SetupFilename); string localAdminGroup = Environment.MachineName + @"\Administrators"; string loginName = setupFile["DatabaseLogin"]; string databaseName = setupFile["DatabaseName"]; string adminKey = "DatabaseConnectionAdmin"; if (setupFile.ContainsKey(adminKey) == false) throw new ApplicationException("DatabaseLogin; DatabaseConnectionAdmin required in SETUP.txt"); string databaseConnectionAdmin = setupFile[adminKey]; int index = loginName.IndexOf(@"\"); if (index == -1) throw new ApplicationException(@"DatabaseUser; SpludlowUser expected DOMAIN\USER in SETUP.txt: " + loginName); string userName = loginName.Substring(index + 1); Spludlow.Data.IDAL dal = Spludlow.Data.DAL.Create(databaseConnectionAdmin); dal.ChangeDatabase(databaseName); dal.UserCreate(userName, loginName, administrator); // will thow if exists !!!!!!!! dont matter as last thing called on db stuff Console.WriteLine("DatabaseUser; Database user created: " + userName + ", " + loginName + ", " + databaseName + " administrator=" + administrator); } public static void DatabaseInsert() { Dictionary setupFile = ReadFile(SetupFilename); bool overWrite = Boolean.Parse(setupFile["OverWrite"]); bool firstHost = Boolean.Parse(setupFile["FirstHost"]); string host = Environment.MachineName; string webServiceAlias = setupFile["Spludlow-WebService"]; string webServiceAdminAlias = setupFile["Spludlow-WebService-Admin"]; string databaseConnection = setupFile["DatabaseConnection"]; // Databse connection string needs to be available to first host only string hostConfiguration = "" + Environment.NewLine; Spludlow.Schema dataSet = new Schema(); Spludlow.Schema.OrganizationsRow orgRow = dataSet.Organizations.NewOrganizationsRow(); orgRow.OrganizationId = setupFile["OrganizationId"]; orgRow.Disabled = false; orgRow.Notes = ""; orgRow.Configuration = ""; orgRow.MasterHostId = host; orgRow.LogHostId = host; orgRow.MailHostAddress = host; orgRow.MailToAddress = setupFile["MailToAddress"]; orgRow.MailFromAddress = setupFile["MailFromAddress"]; dataSet.Organizations.Rows.Add(orgRow); Spludlow.Schema.NetworksRow netRow = dataSet.Networks.NewNetworksRow(); netRow.NetworkId = setupFile["NetworkId"]; netRow.OrganizationId = orgRow.OrganizationId; netRow.Disabled = false; netRow.Notes = ""; netRow.Configuration = ""; netRow.RouterHostId = host; netRow.SmtpServer = setupFile["NetworkSmtpServer"]; netRow.QueueNamespace = setupFile["QueueNamespace"]; dataSet.Networks.Rows.Add(netRow); Spludlow.Schema.HostsRow hostRow = dataSet.Hosts.NewHostsRow(); hostRow.HostId = host; hostRow.NetworkId = netRow.NetworkId; hostRow.Disabled = false; hostRow.Notes = ""; hostRow.Configuration = hostConfiguration; hostRow.LocalWebAddress = "https://" + host.ToLower() + "/" + webServiceAlias + "/"; hostRow.PublicWebAddress = setupFile["PublicWebAddress"] + webServiceAlias + "/"; hostRow.AdminWebAddress = "https://localhost/" + webServiceAdminAlias + "/Admin.svc"; hostRow.DevelopSource = false; hostRow.IgnoreSecurityKey = true; hostRow.SystemUpdateMode = true; dataSet.Hosts.Rows.Add(hostRow); Spludlow.Data.IDAL dal = Spludlow.Data.DAL.Create(databaseConnection); dal.Insert(orgRow); dal.Insert(netRow); dal.Insert(hostRow); Console.WriteLine("DatabaseInsert; Organization, Network, and Host records inserted."); } public static void ConfigApplicationsFiles() { Dictionary setupFile = ReadFile(SetupFilename); Dictionary appProgDirs = ApplicationProgramDirectories(); bool overWrite = Boolean.Parse(setupFile["OverWrite"]); int portNumberStart = Int32.Parse(setupFile["PortNumberStart"]); string serviceProcessName = setupFile["ServiceProcessName"]; string applicationPoolSuffix = setupFile["ApplicationPoolSuffix"]; bool firstHost = Boolean.Parse(setupFile["FirstHost"]); DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "ApplicationId Directory ApplicationType Hosted", "String* String String String", }); string applicationId; applicationId = "Spludlow-Service"; table.Rows.Add(new object[] { applicationId, appProgDirs[applicationId], "Service", serviceProcessName + ":" + portNumberStart }); applicationId = "Spludlow-WebService"; table.Rows.Add(new object[] { applicationId, appProgDirs[applicationId], "Web", applicationId + applicationPoolSuffix }); applicationId = "Spludlow-WebService-Admin"; table.Rows.Add(new object[] { applicationId, appProgDirs[applicationId], "Web", applicationId + applicationPoolSuffix }); applicationId = "Spludlow-Process"; table.Rows.Add(new object[] { applicationId, appProgDirs[applicationId], "Process", null }); if (firstHost == true) { applicationId = "Spludlow-Intranet"; table.Rows.Add(new object[] { applicationId, appProgDirs[applicationId], "Web", applicationId + applicationPoolSuffix }); } string programDataConfig = setupFile["ProgramData"] + @"\Config"; string applicationsFilename = programDataConfig + @"\Applications.txt"; if (File.Exists(applicationsFilename) == true) { if (overWrite == false) throw new ApplicationException("ConfigApplicationsFile; Applications.txt already exist and OverWrite is False: " + applicationsFilename); File.Delete(applicationsFilename); Console.WriteLine("ConfigApplicationsFile; Existing Applications.txt file deleted: " + applicationsFilename); } Spludlow.Data.TextTable.Write(applicationsFilename, table); Console.WriteLine("ConfigApplicationsFile; Applications.txt file created: " + applicationsFilename); StringBuilder serviceConfig = new StringBuilder(); serviceConfig.AppendLine("# Spludlow Service Process Configuration file. Service Process tasks are configured here, There are 2 task kinds; 'Method' and 'Server'. "); serviceConfig.AppendLine("# "); serviceConfig.AppendLine("# 'Method' is the simplest task kind, the specified method is ran on it's own thread. The method is expected to run indefinatly (not return from or reach end of method) "); serviceConfig.AppendLine("# Method [Key] [Assembly] [Type] [Method] [Parameters]"); serviceConfig.AppendLine(); serviceConfig.AppendLine("# Message Queue Processing Methods"); serviceConfig.AppendLine("Method Sys Spludlow Spludlow.QueueProcessor Run Sys"); serviceConfig.AppendLine("Method Run Spludlow Spludlow.QueueProcessor Run Run"); if (firstHost == true) serviceConfig.AppendLine("Method Log Spludlow Spludlow.QueueProcessor Run Log"); serviceConfig.AppendLine(); serviceConfig.AppendLine("# Scheduler - Configure in Scheduler.txt"); serviceConfig.AppendLine("Method Scheduler Spludlow Spludlow.Scheduler Run"); serviceConfig.AppendLine(); serviceConfig.AppendLine("# 'Server' is the other task kind, basically it's a quick way to run WCF NetTcp servers without messing about with .net config files."); serviceConfig.AppendLine("# By default the remote object will be a 'Single'; a single instance is created on the server, subsequent client method calls will use the same, single, instance."); serviceConfig.AppendLine("# Put a star(*) on the end of the Type to configure the remote object 'PerCall'; each and every client method call creates a new instance then disguards it."); serviceConfig.AppendLine("# Server [Key] [Assembly] [Type](*) [Port]"); serviceConfig.AppendLine(); if (firstHost == false) serviceConfig.Append("#"); serviceConfig.AppendLine("Server ParallelResults Spludlow Spludlow.ParallelResults " + (portNumberStart + 1)); serviceConfig.AppendLine(); string serviceConfigFilename = programDataConfig + @"\Spludlow-Service.txt"; if (File.Exists(serviceConfigFilename) == true) { if (overWrite == false) throw new ApplicationException("ConfigApplicationsFile; Spludlow-Service.txt already exist and OverWrite is False: " + serviceConfigFilename); File.Delete(serviceConfigFilename); Console.WriteLine("ConfigApplicationsFile; Existing Spludlow-Service.txt file deleted: " + serviceConfigFilename); } File.WriteAllText(serviceConfigFilename, serviceConfig.ToString()); Console.WriteLine("ConfigApplicationsFile; Spludlow-Service.txt file created: " + serviceConfigFilename); } public static void ConfigFile() { Dictionary setupFile = ReadFile(SetupFilename); bool overWrite = Boolean.Parse(setupFile["OverWrite"]); string databaseConnection = setupFile["DatabaseConnection"]; string programData = setupFile["ProgramData"]; string configFilename = programData + @"\Config\Spludlow.config"; Spludlow.Data.IDAL dal = Spludlow.Data.DAL.Create(databaseConnection); Spludlow.Schema dataSet = new Spludlow.Schema(); foreach (string tableName in new string[] { "Organizations", "Networks", "Hosts" }) dal.Fill(dataSet.Tables[tableName], "SELECT * FROM " + tableName); string config = Spludlow.ConfigMake.Create(dataSet, Environment.MachineName, programData, Spludlow.Config.WCFServerAddressesAltProgData(programData)); if (File.Exists(configFilename) == true) { if (overWrite == false) throw new ApplicationException("ConfigFile; Spludlow.config already exist and OverWrite is False: " + configFilename); File.Delete(configFilename); Console.WriteLine("ConfigFile; Existing Spludlow.config file deleted: " + configFilename); } File.WriteAllText(configFilename, config); Console.WriteLine("ConfigFile; Spludlow.config file created: " + configFilename); } public static void CopyConfigFile(string sourceFilename) { Dictionary setupFile = ReadFile(SetupFilename); bool overWrite = Boolean.Parse(setupFile["OverWrite"]); string programData = setupFile["ProgramData"]; string configFilename = programData + @"\Config\Spludlow.config"; if (File.Exists(configFilename) == true) { if (overWrite == false) throw new ApplicationException("ConfigFile; Spludlow.config already exist and OverWrite is False: " + configFilename); File.Delete(configFilename); Console.WriteLine("ConfigFile; Existing Spludlow.config file deleted: " + configFilename); } string configText = LoadAndFixConfigFile(sourceFilename, programData); File.WriteAllText(configFilename, configText); Console.WriteLine("ConfigFile; Spludlow.config file copied: " + configFilename); } private static string LoadAndFixConfigFile(string sourceFilename, string programData) { string[][] serverAddresses = Spludlow.Config.WCFServerAddressesAltProgData(programData); StringBuilder result = new StringBuilder(); foreach (string line in File.ReadAllLines(sourceFilename)) { string replace; if (line.Contains("") == true) { replace = " "; replace = replace.Replace("@ProgramData", programData); result.AppendLine(replace); continue; } if (line.Contains("") == true) { foreach (string[] pair in serverAddresses) { replace = " "; replace = replace.Replace("@Key", pair[0]); replace = replace.Replace("@Value", pair[1]); result.AppendLine(replace); } continue; } result.AppendLine(line); } return result.ToString(); } public static void WebServiceApplicationPools(bool uninstall) { Dictionary setupFile = ReadFile(SetupFilename); string applicationPoolSuffix = setupFile["ApplicationPoolSuffix"]; bool overWrite = Boolean.Parse(setupFile["OverWrite"]); bool firstHost = Boolean.Parse(setupFile["FirstHost"]); List applicationIds = new List(new string[] { "Spludlow-WebService", "Spludlow-WebService-Admin" }); if (firstHost == true) applicationIds.Add("Spludlow-Intranet"); using (ServerManager serverManager = new ServerManager()) { foreach (string applicationId in applicationIds) { bool admin = false; if (applicationId == "Spludlow-WebService-Admin") admin = true; string userName = setupFile["SpludlowUser"]; string password = setupFile["SpludlowUserPass"]; if (admin == true) { userName = setupFile["SpludlowAdminUser"]; password = setupFile["SpludlowAdminUserPass"]; } string applicationPoolName = applicationId + applicationPoolSuffix; ApplicationPool applicationPool = serverManager.ApplicationPools[applicationPoolName]; if (applicationPool != null) { if (overWrite == false) throw new ApplicationException("OverWrite is not set to True and the Application Pool exists: " + applicationPoolName); serverManager.ApplicationPools.Remove(applicationPool); serverManager.CommitChanges(); Console.WriteLine("WebServiceApplicationPools; Existing Application Pool deleted: " + applicationPoolName); } if (uninstall == false) { applicationPool = serverManager.ApplicationPools.Add(applicationPoolName); applicationPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser; applicationPool.ProcessModel.UserName = userName; applicationPool.ProcessModel.Password = password; applicationPool.ProcessModel.LoadUserProfile = true; serverManager.CommitChanges(); } } } Console.WriteLine("WebServiceApplicationPools; All Application Pools created"); } public static void WebApplications(bool uninstall) { string siteName = "Default Web Site"; Dictionary setupFile = ReadFile(SetupFilename); Dictionary appProgDirs = ApplicationProgramDirectories(); string applicationPoolSuffix = setupFile["ApplicationPoolSuffix"]; bool overWrite = Boolean.Parse(setupFile["OverWrite"]); bool firstHost = Boolean.Parse(setupFile["FirstHost"]); List applicationIds = new List(new string[] { "Spludlow-WebService", "Spludlow-WebService-Admin" }); if (firstHost == true) applicationIds.Add("Spludlow-Intranet"); using (ServerManager serverManager = new ServerManager()) { Site site = serverManager.Sites[siteName]; if (site == null) throw new ApplicationException("Web Site not found: " + siteName); foreach (string applicationId in applicationIds) { string applicationPath = "/" + setupFile[applicationId]; string applicationPoolName = applicationId + applicationPoolSuffix; Application application = site.Applications[applicationPath]; if (application != null) { if (overWrite == false) throw new ApplicationException("OverWrite is not set to True and the Web Application exists: " + applicationPath); site.Applications.Remove(application); Console.WriteLine("WebApplications; Existing Web Application deleted: " + applicationPath); } if (uninstall == false) { application = site.Applications.Add(applicationPath, appProgDirs[applicationId]); application.ApplicationPoolName = applicationPoolName; } } serverManager.CommitChanges(); } Console.WriteLine("WebApplications; All Web Applications created"); } public static void ServiceProcess(bool uninstall) { Dictionary setupFile = ReadFile(SetupFilename); Dictionary appProgDirs = ApplicationProgramDirectories(); string serviceProcessName = setupFile["ServiceProcessName"]; bool overWrite = Boolean.Parse(setupFile["OverWrite"]); string applicationId = "Spludlow-Service"; string serviceFilename = appProgDirs[applicationId] + @"\" + applicationId + ".exe"; string userName = setupFile["SpludlowUser"]; string password = setupFile["SpludlowUserPass"]; if (Spludlow.ServiceProcesses.Exists(serviceProcessName) == true) { if (overWrite == false) throw new ApplicationException("OverWrite is not set to True and the Service Process exists: " + serviceProcessName); Console.WriteLine("ServiceProcess; Allready exists: " + serviceProcessName); ServiceProcessInstall(serviceFilename, null, null, true); // do before with original uninstaller ???? only name matters, has to be same ??? Console.WriteLine("ServiceProcess; Existing uninstalled: " + serviceProcessName); } if (uninstall == true) return; ServiceProcessInstall(serviceFilename, userName, password, false); Console.WriteLine("ServiceProcess; New Installed: " + serviceProcessName); } public static void ServiceProcessInstall(string serviceFilename, string userName, string password, bool uninstall) { StringBuilder arguments = new StringBuilder("/unattended"); if (uninstall == false) { arguments.Append(" /username=\"@username\" /password=\"@password\""); arguments.Replace("@username", userName); arguments.Replace("@password", password); } else { arguments.Insert(0, "/uninstall "); } arguments.Append(" \""); arguments.Append(serviceFilename); arguments.Append("\""); string installUtil = @"C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe"; Spludlow.SpawnProcess.ProcessExitInfo exitInfo = Spludlow.SpawnProcess.Run(installUtil, arguments.ToString(), 180); Console.WriteLine("InstallUtil; Output: ================================"); Console.Write(exitInfo.StandardOutput); Console.WriteLine("====================================================="); if (exitInfo.ExitCode != 0 || exitInfo.StandardError.Length > 0) throw new ApplicationException("InstallUtil; Exit code or error output: " + exitInfo.ExitCode + ", " + exitInfo.StandardError); } public static Dictionary ReadFile(string filename) { Dictionary setupValues = new Dictionary(); foreach (string rawLine in File.ReadAllLines(filename)) { string line = rawLine.Trim(); if (line.Length == 0 || line.StartsWith("#") == true) continue; string[] words = Spludlow.Text.Split(line, '\t', true); if (words.Length != 2) throw new ApplicationException("Bad line in SETUP file: " + line); setupValues.Add(words[0], words[1]); } return setupValues; } public static void ReCreateDirectoryKeepWebConfig(string directory) { string filename = directory + @"\web.config"; byte[] data = File.ReadAllBytes(filename); System.Threading.Thread.Sleep(0); Directory.Delete(directory, true); System.Threading.Thread.Sleep(0); Directory.CreateDirectory(directory); System.Threading.Thread.Sleep(0); File.WriteAllBytes(filename, data); File.SetAttributes(filename, FileAttributes.Hidden); } public static void PrepareBinaries(string[] projectNames, string downloadsDirectory, string historyDirectory, string sourceBrowseDirectory, string readmeFilename, string downloadsIncludeDirectory) { string downloadsWeb = "./"; string version = Spludlow.Code.GetVersionNumber(); string frameworkVersion = Spludlow.Code.GetFrameworkVersion(); string currentReleaseDirectory = historyDirectory + @"\" + version; string currentReleaseDirectoryBin = currentReleaseDirectory + @"\binaries"; string currentReleaseDirectorySrc = currentReleaseDirectory + @"\source"; if (Directory.Exists(currentReleaseDirectory) == true) throw new ApplicationException("Setup PrepareBinaries; This release already exists: " + currentReleaseDirectory); Directory.CreateDirectory(currentReleaseDirectory); Directory.CreateDirectory(currentReleaseDirectoryBin); Directory.CreateDirectory(currentReleaseDirectorySrc); // Clear source browse ReCreateDirectoryKeepWebConfig(sourceBrowseDirectory); // Clear downloads directory ReCreateDirectoryKeepWebConfig(downloadsDirectory); // Download includes foreach (string filename in Directory.GetFiles(downloadsIncludeDirectory)) { File.Copy(filename, currentReleaseDirectory + @"\" + Path.GetFileName(filename)); } Spludlow.Release.MakeAllNew(); // BIN, SRC, SETUP DataTable indexTable = Spludlow.Data.TextTable.ReadText(new string[] { "ProjectName ArchiveType Version NetVersion Filename DownloadLink FileSize FileSizeText MD5 SHA1", "String* String* String String String String Int64 String String String", }); // Setup Archive string setupFilename = currentReleaseDirectory + @"\SpludlowSetup" + "-" + version + "-net" + frameworkVersion + "-setup.7z"; PrepareSpludlowSetup(setupFilename, readmeFilename); AddIndexRow(indexTable, "SpludlowSetup", "SETUP", version, frameworkVersion, downloadsWeb, setupFilename); // Binary Archives string newDirectory = Spludlow.Config.ProgramData + @"\Release\New"; foreach (string projectName in projectNames) { string sourceDirectory = newDirectory + @"\" + projectName; if (Directory.Exists(sourceDirectory) == false) throw new ApplicationException("PrepareBinaries; project new directory not there: " + sourceDirectory); string archiveFilename = currentReleaseDirectoryBin + @"\" + projectName + "-" + version + "-net" + frameworkVersion + "-bin.7z"; if (File.Exists(archiveFilename) == true) File.Delete(archiveFilename); File.Copy(readmeFilename, sourceDirectory + @"\README.txt"); Spludlow.Archive.Create(archiveFilename, sourceDirectory); AddIndexRow(indexTable, projectName, "BIN", version, frameworkVersion, downloadsWeb + "binaries/", archiveFilename); } List validExtentions = new List(new string[] { ".cs", ".aspx", ".ascx", ".svc", ".master", ".txt", ".config", }); DataTable sourceTable = Spludlow.Config.DevelopSources().Tables[0]; using (Spludlow.TempDirectory tempDir = new TempDirectory()) { foreach (string projectName in projectNames) { DataRow row = sourceTable.Rows.Find(projectName); if (row == null) throw new ApplicationException("PrepareBinaries; Project source code row not found: " + projectName); string sourceCodeDirectory = (string)row["Directory"]; if (Directory.Exists(sourceCodeDirectory) == false) throw new ApplicationException("PrepareBinaries; Project source code Directory not found: " + sourceCodeDirectory); // Source Archives string sourceDirectory = tempDir.Path + @"\" + projectName; Spludlow.Io.Dirs.Copy(sourceCodeDirectory, sourceDirectory); foreach (string subDirName in new string[] { "bin", "obj" }) { string removeDirectory = sourceDirectory + @"\" + subDirName; if (Directory.Exists(removeDirectory) == true) Directory.Delete(removeDirectory, true); } string configFilename = sourceDirectory + @"\app.config"; // Remove Unwanted config files if (File.Exists(configFilename) == true) { string binDirectory = sourceCodeDirectory + @"\bin\Release"; if (Directory.Exists(binDirectory) == true) { string exeFilename = binDirectory + @"\" + projectName + ".exe"; if (File.Exists(exeFilename) == false) { File.Delete(configFilename); Spludlow.Log.Warning("PrepareBinaries, Source Archive; Unwanted config file: " + configFilename); } } } string archiveFilename = currentReleaseDirectorySrc + @"\" + projectName + "-" + version + "-src.7z"; if (File.Exists(archiveFilename) == true) File.Delete(archiveFilename); Spludlow.Archive.Create(archiveFilename, sourceDirectory); AddIndexRow(indexTable, projectName, "SRC", version, frameworkVersion, downloadsWeb + "source/", archiveFilename); // Source Browse foreach (string rawFilename in Directory.GetFiles(sourceCodeDirectory, "*", SearchOption.AllDirectories)) { string filename = rawFilename.ToLower(); string extention = Path.GetExtension(filename); if (validExtentions.Contains(extention) == false) continue; if (extention == ".cs" && Spludlow.Code.ValidCSharpFilename(filename) == false) continue; if (filename.Contains(@"\bin\") == true) continue; if (filename.Contains(@"\obj\") == true) continue; filename = rawFilename; string targetFilename = sourceBrowseDirectory + @"\" + projectName + filename.Substring(sourceCodeDirectory.Length) + ".txt"; string targetDirectory = Path.GetDirectoryName(targetFilename); if (Directory.Exists(targetDirectory) == false) Directory.CreateDirectory(targetDirectory); File.Copy(filename, targetFilename); } } } Spludlow.Log.Report("PrepareBinaries Index", indexTable); Spludlow.Data.TextTable.Write(currentReleaseDirectory + @"\Index.txt", indexTable); // Copy from last history to downloads directory foreach (string filename in Directory.GetFiles(currentReleaseDirectory, "*", SearchOption.AllDirectories)) { string targetFilename = downloadsDirectory + filename.Substring(currentReleaseDirectory.Length); string targetDir = Path.GetDirectoryName(targetFilename); if (Directory.Exists(targetDir) == false) Directory.CreateDirectory(targetDir); File.Copy(filename, targetFilename); } } private static void AddIndexRow(DataTable indexTable, string project, string type, string version, string frameworkVersion, string webPrefix, string filename) { string name = Path.GetFileName(filename); long length = Spludlow.Io.Files.FileLength(filename); indexTable.Rows.Add(project, type, version, frameworkVersion, name, webPrefix + name, length, Spludlow.Text.DataSize(length), Spludlow.Hashing.MD5HexFile(filename), Spludlow.Hashing.SHA1HexFile(filename)); } public static void PrepareSpludlowSetup(string targetArchiveFilename, string readmeFilename) { string[] projectNames = new string[] { "Spludlow-Intranet", "Spludlow-Process", "Spludlow-Service", "Spludlow-Service32", "Spludlow-WebService", "Spludlow-WebService-Admin", }; using (Spludlow.TempDirectory tempDir = new TempDirectory()) { string setupDirectory = tempDir + @"\SpludlowSetupV1"; Directory.CreateDirectory(setupDirectory); File.Copy(readmeFilename, setupDirectory + @"\README.txt"); string directory; directory = setupDirectory + @"\ProgramData"; Directory.CreateDirectory(directory); directory = setupDirectory + @"\ProgramData\Data"; Directory.CreateDirectory(directory); string sourceData = Spludlow.Config.ProgramData + @"\Data"; string[] dataFilenames = new string[] { "ASCII.txt", "BarCode128.txt", "BarCodeRM4SCC.txt", "BarCodeRM4SCCchecksum.txt", "CMYKColors.txt", "DataTypes.txt", "HttpStatusCodes.txt", "ISO3166.txt", "PostCodeAreas.txt", "PostCodeDistricts.txt", "UnicodeBlocks.txt", }; foreach (string dataFilename in dataFilenames) File.Copy(sourceData + @"\" + dataFilename, setupDirectory + @"\ProgramData\Data\" + dataFilename); Spludlow.Data.IDAL database = Spludlow.Data.DAL.Create("@Spludlow"); DataSet schema = database.Schema(); Spludlow.Data.TextTable.WriteDirectory(setupDirectory + @"\Schema", schema); foreach (string sourceFilename in Directory.GetFiles(@"D:\Develop\SetupInclude")) File.Copy(sourceFilename, setupDirectory + @"\" + Path.GetFileName(sourceFilename)); File.Copy(Spludlow.Config.ProgramData + @"\Release\New\Spludlow-Process\Spludlow-Process.exe", setupDirectory + @"\Spludlow-Process.exe"); File.Copy(Spludlow.Config.ProgramData + @"\Release\New\Spludlow-Process\Spludlow.dll", setupDirectory + @"\Spludlow.dll"); string newDirectory = Spludlow.Config.ProgramData + @"\Release\New"; foreach (string projectName in projectNames) { string sourceDirectory = newDirectory + @"\" + projectName; if (Directory.Exists(sourceDirectory) == false) throw new ApplicationException("PrepareSpludlowSetup; project new directory not there: " + sourceDirectory); string targetDirectory = setupDirectory + @"\" + projectName; if (Directory.Exists(targetDirectory) == true) Directory.Delete(targetDirectory, true); Spludlow.Io.Dirs.Copy(sourceDirectory, targetDirectory); } Spludlow.Archive.Create(targetArchiveFilename, setupDirectory); } } } }