// Copyright (c) 2011, Outercurve Foundation.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Collections.Generic;
using System.Text;
using WebsitePanel.Installer.Core;
using WebsitePanel.Installer.Common;
using System.Data;
using System.Threading;
using WebsitePanel.Installer.Configuration;
using System.IO;
using System.Collections;
namespace WebsitePanel.SilentInstaller
{
class Program
{
public const string ComponentNameParam = "cname";
public static readonly Hashtable ServiceCliParams = new Hashtable
{
{ Global.CLI.WebSiteIP, Global.Parameters.WebSiteIP }, // IP Address
{ Global.CLI.ServiceAccountPassword, Global.Parameters.UserPassword }, // Service account password
{ Global.CLI.ServiceAccountDomain, Global.Parameters.UserDomain }, // Service account domain (AD only)
{ Global.CLI.ServiceAccountName, Global.Parameters.UserAccount }, // Service account name
{ Global.CLI.WebSitePort, Global.Parameters.WebSitePort }, // TCP Port
{ Global.CLI.WebSiteDomain, Global.Parameters.WebSiteDomain } // Website domain (if any assigned)
};
public static readonly Hashtable ServerCliParams = new Hashtable
{
{ Global.Server.CLI.ServerPassword, Global.Parameters.ServerPassword }, // Server password
};
public static readonly Hashtable EntServerCliParams = new Hashtable
{
{ Global.EntServer.CLI.ServeradminPassword, Global.Parameters.ServerAdminPassword }, // serveradmin password
{ Global.EntServer.CLI.DatabaseName, Global.Parameters.DatabaseName }, // Database name
{ Global.EntServer.CLI.DatabaseServer, Global.Parameters.DatabaseServer }, // Database server
{ Global.EntServer.CLI.DbServerAdmin, Global.Parameters.DbServerAdmin }, // Database server administrator login
{ Global.EntServer.CLI.DbServerAdminPassword, Global.Parameters.DbServerAdminPassword }, // Database server administrator password
};
public static readonly Hashtable WebPortalCliParams = new Hashtable
{
{ Global.WebPortal.CLI.EnterpriseServerUrl, Global.Parameters.EnterpriseServerUrl }, // Enterprise Server URL
};
public static readonly Hashtable StdServerSetupCliParams = new Hashtable
{
{ Global.EntServer.CLI.DatabaseServer, Global.Parameters.DatabaseServer },
{ Global.EntServer.CLI.DatabaseName, Global.Parameters.DatabaseName },
{ Global.EntServer.CLI.DbServerAdmin , Global.Parameters.DbServerAdmin },
{ Global.EntServer.CLI.DbServerAdminPassword, Global.Parameters.DbServerAdminPassword },
{ Global.EntServer.CLI.ServeradminPassword, Global.Parameters.ServerAdminPassword }
};
[STAThread]
static int Main(string[] args)
{
//
Utils.FixConfigurationSectionDefinition();
//
// Ensure arguments supplied for the application
if (args.Length == 0)
{
Log.WriteError(Global.Messages.NoInputParametersSpecified);
return Global.Messages.NoInputParametersSpecifiedError;
}
// Check user's security permissions
if (!Utils.CheckSecurity())
{
ShowSecurityError();
return Global.Messages.NotEnoughPermissionsErrorCode;
}
// Check administrator permissions
if (!Utils.IsAdministrator())
{
ShowSecurityError();
return Global.Messages.NotEnoughPermissionsErrorCode;
}
// Check for running instance
if (!Utils.IsNewInstance())
{
ShowInstanceRunningErrorMessage();
return Global.Messages.AnotherInstanceIsRunningError;
}
//
var cname = GetCommandLineArgumentValue(ComponentNameParam);
if (Utils.CheckForInstalledComponent(cname))
{
Log.WriteError(Global.Messages.ComponentIsAlreadyInstalled);
//
return Global.Messages.ComponentIsAlreadyInstalledError;
}
try
{
// Make sure no other installations could be run at the same time
Utils.SaveMutex();
//
Log.WriteApplicationStart();
//check OS version
Log.WriteInfo("{0} detected", Global.OSVersion);
//check IIS version
if (Global.IISVersion.Major == 0)
Log.WriteError("IIS not found.");
else
Log.WriteInfo("IIS {0} detected", Global.IISVersion);
var service = ServiceProviderProxy.GetInstallerWebService();
var record = default(DataRow);
//
var ds = service.GetAvailableComponents();
//
foreach (DataRow row in ds.Tables[0].Rows)
{
string componentCode = Utils.GetDbString(row["ComponentCode"]);
//
if (!String.Equals(componentCode, cname, StringComparison.OrdinalIgnoreCase))
{
continue;
}
//
record = row;
break;
}
//
if (record == null)
{
Log.WriteError(String.Format("{0} => {1}", ComponentNameParam, cname));
Log.WriteInfo("Incorrect component name specified");
return Global.Messages.UnknownComponentCodeError;
}
//
var cli_args = ParseInputFromCLI(cname);
//
StartInstaller(record, cli_args);
//
return Global.Messages.SuccessInstallation;
}
catch (Exception ex)
{
Log.WriteError("Failed to install the component", ex);
//
return Global.Messages.InstallationError;
}
finally
{
Log.WriteApplicationEnd();
}
}
private static void ShowInstanceRunningErrorMessage()
{
Log.WriteError(Global.Messages.AnotherInstanceIsRunning);
}
private static void ShowSecurityError()
{
Log.WriteError(Global.Messages.NotEnoughPermissionsError);
}
///
/// Parses user input from the command-line for the component specified and returns it in the form of a Hashtable to pass run the installer with arguments then.
///
/// Component code whose input from the command-line is being parsed
/// Thrown when wrong component code is specified. See Global class for supported component codes.
///
static Hashtable ParseInputFromCLI(string cname)
{
//
if (cname.Equals(Global.Server.ComponentCode, StringComparison.OrdinalIgnoreCase))
{
//
return LoadInputFromCLI(
ServerCliParams,
ServiceCliParams,
output: new Hashtable
{
{ Global.Parameters.WebSiteIP, Global.Server.DefaultIP },
{ Global.Parameters.WebSiteDomain, String.Empty },
{ Global.Parameters.WebSitePort, Global.Server.DefaultPort },
{ Global.Parameters.UserAccount, Global.Server.ServiceAccount },
{ Global.Parameters.UserDomain, String.Empty },
{ Global.Parameters.UserPassword, String.Empty },
{ Global.Parameters.ServerPassword, null } // Required CLI parameters must be initialized with null value!
}
);
}
else if (cname.Equals(Global.EntServer.ComponentCode, StringComparison.OrdinalIgnoreCase))
{
//
return LoadInputFromCLI(
EntServerCliParams,
ServiceCliParams,
output: new Hashtable
{
{ Global.Parameters.WebSiteIP, Global.EntServer.DefaultIP },
{ Global.Parameters.WebSiteDomain, String.Empty },
{ Global.Parameters.WebSitePort, Global.EntServer.DefaultPort },
{ Global.Parameters.UserAccount, Global.EntServer.ServiceAccount },
{ Global.Parameters.UserDomain, String.Empty },
{ Global.Parameters.UserPassword, String.Empty },
{ Global.Parameters.DatabaseName, Global.EntServer.DefaultDatabase },
{ Global.Parameters.DbServerAdmin, String.Empty },
{ Global.Parameters.DbServerAdminPassword, String.Empty },
{ Global.Parameters.DatabaseServer, Global.EntServer.DefaultDbServer },
{ Global.Parameters.ServerAdminPassword, null } // Required CLI parameters must be initialized with null value!
}
);
}
else if (cname.Equals(Global.WebPortal.ComponentCode, StringComparison.OrdinalIgnoreCase))
{
//
return LoadInputFromCLI(
WebPortalCliParams,
ServiceCliParams,
output: new Hashtable
{
{ Global.Parameters.WebSiteIP, Global.WebPortal.DefaultIP },
{ Global.Parameters.WebSiteDomain, String.Empty },
{ Global.Parameters.WebSitePort, Global.WebPortal.DefaultPort },
{ Global.Parameters.UserAccount, Global.WebPortal.ServiceAccount },
{ Global.Parameters.UserDomain, String.Empty },
{ Global.Parameters.UserPassword, String.Empty },
{ Global.Parameters.EnterpriseServerUrl, null } // Required CLI parameters must be initialized with null value!
}
);
}
else if (cname.Equals(Global.StandaloneServer.ComponentCode, StringComparison.OrdinalIgnoreCase))
{
return LoadInputFromCLI(
StdServerSetupCliParams,
ServiceCliParams,
output: new Hashtable
{
{ Global.Parameters.WebSiteIP, Global.WebPortal.DefaultIP },
{ Global.Parameters.WebSiteDomain, String.Empty },
{ Global.Parameters.WebSitePort, Global.WebPortal.DefaultPort },
{ Global.Parameters.DatabaseName, Global.EntServer.DefaultDatabase },
{ Global.Parameters.DatabaseServer, Global.EntServer.DefaultDbServer },
{ Global.Parameters.DbServerAdmin, String.Empty },
{ Global.Parameters.DbServerAdminPassword, String.Empty },
{ Global.Parameters.ServerAdminPassword, String.Empty }
}
);
}
//
throw new Exception("Wrong component code!");
}
///
/// Loads an input from the command-line interface into a Hashtable instance to use for calls to the Installer and checks whether or not the required parameters are set.
///
/// A collection with service-specific parameter names to match the input from the command-line interface (CLI)
/// A collection with service-generic parameter names to match the input from the command-line interface (CLI)
/// An output storage to put the input data into
/// This method
static Hashtable LoadInputFromCLI(Hashtable inputA, Hashtable inputB, Hashtable output)
{
// Process service
foreach (var item in inputA.Keys)
{
var cli_argv = GetCommandLineArgumentValue(item as String);
//
if (String.IsNullOrEmpty(cli_argv))
continue;
// Assign argument value from CLI
output[inputA[item]] = cli_argv;
}
//
foreach (var item in inputB.Keys)
{
var cli_argv = GetCommandLineArgumentValue(item as String);
//
if (String.IsNullOrEmpty(cli_argv))
continue;
// Assign argument value from CLI
output[inputB[item]] = cli_argv;
}
// Ensure all required parameters are set
foreach (var item in output.Keys)
{
// If a parameter is required, then you should assign null value
if (output[item] == null)
{
throw new ArgumentNullException(item as String);
}
}
//
return output;
}
static void StartInstaller(DataRow row, Hashtable args)
{
string applicationName = Utils.GetDbString(row["ApplicationName"]);
string componentName = Utils.GetDbString(row["ComponentName"]);
string componentCode = Utils.GetDbString(row["ComponentCode"]);
string componentDescription = Utils.GetDbString(row["ComponentDescription"]);
string component = Utils.GetDbString(row["Component"]);
string version = Utils.GetDbString(row["Version"]);
string fileName = row["FullFilePath"].ToString();
string installerPath = Utils.GetDbString(row["InstallerPath"]);
string installerType = Utils.GetDbString(row["InstallerType"]);
try
{
// download installer
var loader = new Loader(fileName);
//
loader.OperationCompleted += new EventHandler((object sender, EventArgs e) =>
{
Log.WriteInfo("Download completed!");
//
string tmpFolder = FileUtils.GetTempDirectory();
string path = Path.Combine(tmpFolder, installerPath);
//Update();
string method = "Install";
Log.WriteStart(string.Format("Running installer {0}.{1} from {2}", installerType, method, path));
//prepare installer args
args[Global.Parameters.ComponentName] = componentName;
args[Global.Parameters.ApplicationName] = applicationName;
args[Global.Parameters.ComponentCode] = componentCode;
args[Global.Parameters.ComponentDescription] = componentDescription;
args[Global.Parameters.Version] = version;
args[Global.Parameters.InstallerFolder] = tmpFolder;
args[Global.Parameters.InstallerPath] = installerPath;
args[Global.Parameters.InstallerType] = installerType;
args[Global.Parameters.Installer] = Path.GetFileName(fileName);
args[Global.Parameters.BaseDirectory] = FileUtils.GetCurrentDirectory();
args[Global.Parameters.IISVersion] = Global.IISVersion;
args[Global.Parameters.ShellVersion] = AssemblyLoader.GetShellVersion();
args[Global.Parameters.ShellMode] = Global.SilentInstallerShell;
args[Global.Parameters.SetupXml] = String.Empty;
// Run the installer
var res = AssemblyLoader.Execute(path, installerType, method, new object[] { args });
Log.WriteInfo(string.Format("Installer returned {0}", res));
Log.WriteEnd("Installer finished");
// Remove temporary directory
FileUtils.DeleteTempDirectory();
});
loader.OperationFailed += new EventHandler>(loader_OperationFailed);
loader.ProgressChanged += new EventHandler>(loader_ProgressChanged);
loader.StatusChanged += new EventHandler>(loader_StatusChanged);
//
loader.LoadAppDistributive();
}
catch (Exception ex)
{
Log.WriteError("Installer error", ex);
//AppContext.AppForm.ShowError(ex);
}
finally
{
//this.componentSettingsXml = null;
//this.componentCode = null;
}
}
static void loader_StatusChanged(object sender, LoaderEventArgs e)
{
if (String.IsNullOrEmpty(e.EventData))
Log.WriteInfo(e.StatusMessage);
else
Log.WriteInfo("{0} {1}", e.StatusMessage, e.EventData);
}
static void loader_ProgressChanged(object sender, LoaderEventArgs e)
{
if (!String.IsNullOrEmpty(e.StatusMessage))
Log.WriteInfo("{0} {1}%", e.StatusMessage, e.EventData);
else
Log.WriteInfo("Current progress is {0}%", e.EventData);
}
static void loader_OperationFailed(object sender, LoaderEventArgs e)
{
Log.WriteInfo(e.EventData.ToString());
}
///
/// Check for existing command line argument
///
private static bool CheckCommandLineArgument(string argName)
{
string[] args = Environment.GetCommandLineArgs();
for (int i = 1; i < args.Length; i++)
{
string arg = args[i];
if (string.Equals(arg, argName, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
return false;
}
///
/// Check for existing command line argument
///
private static string GetCommandLineArgumentValue(string argName)
{
string key = "/" + argName.ToLower() + ":";
string[] args = Environment.GetCommandLineArgs();
for (int i = 1; i < args.Length; i++)
{
string arg = args[i].ToLower();
if (arg.StartsWith(key))
{
// Remove leading and trailing double quotes if any
return args[i].Substring(key.Length).TrimStart('"').TrimEnd('"');
}
}
return null;
}
}
}