/// <summary> /// Installs the specified MSI. /// </summary> /// <param name="packagePath">The full path to the MSI package.</param> /// <param name="logFile">The full path of the log file.</param> /// <returns>An error code indicating the result of the operation.</returns> protected uint InstallMsi(string packagePath, string logFile) { // Make sure the package we're going to run is coming from the cache. if (!packagePath.StartsWith(Cache.PackageCacheRoot)) { return(Error.INSTALL_PACKAGE_INVALID); } Elevate(); if (IsElevated) { ConfigureInstall(logFile); return(WindowsInstaller.InstallProduct(packagePath, s_installProperties)); } else if (IsClient) { InstallResponseMessage response = Dispatcher.SendMsiRequest(InstallRequestType.InstallMsi, logFile, packagePath); ExitOnFailure(response, "Failed to install MSI."); return(response.Error); } throw new InvalidOperationException($"Invalid configuration: elevated: {IsElevated}, client: {IsClient}"); }
/// <summary> /// Determines the state of the specified product. /// </summary> /// <param name="productCode">The product code of the MSI to detect.</param> /// <param name="installedVersion">If detected, contains the version of the installed MSI.</param> /// <returns>The detect state of the specified MSI.</returns> private DetectState Detect(string productCode, out string installedVersion) { uint error = WindowsInstaller.GetProductInfo(productCode, InstallProperty.VERSIONSTRING, out installedVersion); DetectState state = error == Error.SUCCESS ? DetectState.Present : (error == Error.UNKNOWN_PRODUCT) || (error == Error.UNKNOWN_PROPERTY) ? DetectState.Absent : DetectState.Unknown; ExitOnError(state == DetectState.Unknown, error, $"Failed to detect MSI package with ProductCode={productCode}."); Log?.LogMessage($"Detected package, ProductCode: {productCode}, version: {(string.IsNullOrWhiteSpace(installedVersion) ? "n/a" : $"{installedVersion}")}, state: {state}.");
public void TestShortcut() { WindowsInstaller.CreateDesktopIcon("Project Dollhouse", Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "\\Project Dollhouse\\" + m_PDEXECUTABLE, Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "\\Project Dollhouse\\"); Assert.IsTrue(File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\Project Dollhouse.lnk")); }
/// <summary> /// Configures the installer UI and logging operations before starting an operation. /// </summary> /// <param name="logFile">The path of the log file.</param> protected void ConfigureInstall(string logFile) { uint error = Error.SUCCESS; // Turn off the MSI UI. _ = WindowsInstaller.SetInternalUI(InstallUILevel.None); // The log file must be created before calling MsiEnableLog and we should avoid having active handles // against it. FileStream logFileStream = File.Create(logFile); logFileStream.Close(); error = WindowsInstaller.EnableLog(InstallLogMode.DEFAULT | InstallLogMode.VERBOSE, logFile, InstallLogAttributes.NONE); // We can report issues with the log file creation, but shouldn't fail the workload operation. LogError(error, $"Failed to configure log file: {logFile}"); }
/// <summary> /// Repairs the specified MSI package. /// </summary> /// <param name="productCode">The product code of the MSI to repair.</param> /// <param name="logFile">The full path of the log file.</param> /// <returns>An error code indicating the result of the operation.</returns> protected uint RepairMsi(string productCode, string logFile) { Elevate(); if (IsElevated) { ConfigureInstall(logFile); return(WindowsInstaller.ReinstallProduct(productCode, DefaultReinstallMode)); } else if (IsClient) { InstallResponseMessage response = Dispatcher.SendMsiRequest(InstallRequestType.RepairMsi, logFile, null, productCode); ExitOnFailure(response, "Failed to repair MSI."); return(response.Error); } throw new InvalidOperationException($"Invalid configuration: elevated: {IsElevated}, client: {IsClient}"); }
/// <summary> /// Uninstalls the MSI using its provided product code. /// </summary> /// <param name="productCode">The product code of the MSI to uninstall.</param> /// <param name="logFile">The full path of the log file.</param> /// <returns>An error code indicating the result of the operation.</returns> protected uint UninstallMsi(string productCode, string logFile) { Elevate(); if (IsElevated) { ConfigureInstall(logFile); return(WindowsInstaller.ConfigureProduct(productCode, WindowsInstaller.INSTALLLEVEL_DEFAULT, InstallState.ABSENT, s_uninstallProperties)); } else if (IsClient) { InstallResponseMessage response = Dispatcher.SendMsiRequest(InstallRequestType.UninstallMsi, logFile, null, productCode); ExitOnFailure(response, "Failed to uninstall MSI."); return(response.Error); } throw new InvalidOperationException($"Invalid configuration: elevated: {IsElevated}, client: {IsClient}"); }
/// <summary> /// Determines the state of the specified product. /// </summary> /// <param name="productCode">The product code of the MSI to detect.</param> /// <param name="installedVersion">If detected, contains the version of the installed MSI.</param> /// <returns>The detect state of the specified MSI.</returns> private DetectState DetectPackage(string productCode, out Version installedVersion) { installedVersion = default; uint error = WindowsInstaller.GetProductInfo(productCode, InstallProperty.VERSIONSTRING, out string versionValue); DetectState state = error == Error.SUCCESS ? DetectState.Present : (error == Error.UNKNOWN_PRODUCT) || (error == Error.UNKNOWN_PROPERTY) ? DetectState.Absent : DetectState.Unknown; ExitOnError(state == DetectState.Unknown, error, $"DetectPackage: Failed to detect MSI package, ProductCode: {productCode}."); if (state == DetectState.Present) { if (!Version.TryParse(versionValue, out installedVersion)) { Log?.LogMessage($"DetectPackage: Failed to parse version: {versionValue}."); } } Log?.LogMessage($"DetectPackage: ProductCode: {productCode}, version: {installedVersion?.ToString() ?? "n/a"}, state: {state}."); return(state); }
void InstallMsi(string path) { // Configure event handler for install messages UserInterfaceHandler ux = new UserInterfaceHandler(InstallLogMode.ACTIONDATA | InstallLogMode.ACTIONSTART | InstallLogMode.PROGRESS); ux.ActionData += OnActionData; ux.ActionStart += OnActionStart; ux.Progress += OnProgress; ProgressPhase = 0; Console.WriteLine(); ActionTop = Console.CursorTop; ProgressBarTop = ActionTop + 1; // Make sure we run quietly. Be careful, we won't be prompted to elevate. WindowsInstaller.SetInternalUI(InstallUILevel.None); uint error = WindowsInstaller.InstallProduct(path, "MSIFASTINSTALL=7 REBOOT=ReallySuppress"); Console.CursorTop = ProgressBarTop + 1; Console.CursorLeft = 0; Console.CursorTop = ActionTop; ClearLine(); Console.CursorTop = ProgressBarTop; ClearLine(); if ((error != Error.SUCCESS) && (error != Error.SUCCESS_REBOOT_INITIATED) && (error != Error.SUCCESS_REBOOT_REQUIRED)) { throw new WindowsInstallerException((int)error); } else { Console.WriteLine("Done!"); } }
public void TestRegistry() { /*m_CrossThreadRunner.RunInSTA( * delegate * { * MainWindow Window = new MainWindow(); * * if (!Window.CheckRegistry()) * { * Window.CreateRegistry(); * * Assert.IsTrue(Window.CheckRegistry()); * } * });*/ if (!WindowsInstaller.CheckRegistry()) { WindowsInstaller.CreateRegistry(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "Maxis\\The Sims Online\\"); Assert.IsTrue(WindowsInstaller.CheckRegistry()); } Assert.Pass(); }
static void Main(string[] args) { var arguments = new HostArguments(args); if (arguments.Help) { arguments.PrintUsage(); return; } assemblyScannerResults = AssemblyScanner.GetScannableAssemblies(); var endpointTypeDeterminer = new EndpointTypeDeterminer(assemblyScannerResults, () => ConfigurationManager.AppSettings["EndpointConfigurationType"]); var endpointConfigurationType = endpointTypeDeterminer.GetEndpointConfigurationTypeForHostedEndpoint(arguments); var endpointConfigurationFile = endpointConfigurationType.EndpointConfigurationFile; var endpointName = endpointConfigurationType.EndpointName; var serviceName = endpointConfigurationType.ServiceName; var endpointVersion = endpointConfigurationType.EndpointVersion; var displayName = serviceName + "-" + endpointVersion; if (arguments.SideBySide) { serviceName += "-" + endpointVersion; } //Add the endpoint name so that the new appdomain can get it if (arguments.EndpointName == null && !String.IsNullOrEmpty(endpointName)) { args = args.Concat(new[] { String.Format(@"/endpointName={0}", endpointName) }).ToArray(); } //Add the ScannedAssemblies name so that the new appdomain can get it if (arguments.ScannedAssemblies.Count == 0) { args = assemblyScannerResults.Assemblies.Select(s => s.ToString()).Aggregate(args, (current, result) => current.Concat(new[] { String.Format(@"/scannedAssemblies={0}", result) }).ToArray()); } //Add the endpointConfigurationType name so that the new appdomain can get it if (arguments.EndpointConfigurationType == null) { args = args.Concat(new[] { String.Format(@"/endpointConfigurationType={0}", endpointConfigurationType.AssemblyQualifiedName) }).ToArray(); } if (arguments.Install) { WindowsInstaller.Install(args, endpointConfigurationFile); } IRunConfiguration cfg = RunnerConfigurator.New(x => { x.ConfigureServiceInIsolation <WindowsHost>(endpointConfigurationType.AssemblyQualifiedName, c => { c.ConfigurationFile(endpointConfigurationFile); c.WhenStarted(service => service.Start()); c.WhenStopped(service => service.Stop()); c.CommandLineArguments(args, () => SetHostServiceLocatorArgs); c.CreateServiceLocator(() => new HostServiceLocator()); }); if (arguments.Username != null && arguments.Password != null) { x.RunAs(arguments.Username, arguments.Password); } else { x.RunAsLocalSystem(); } if (arguments.StartManually) { x.DoNotStartAutomatically(); } x.SetDisplayName(arguments.DisplayName ?? displayName); x.SetServiceName(serviceName); x.SetDescription(arguments.Description ?? string.Format("NServiceBus Endpoint Host Service for {0}", displayName)); var serviceCommandLine = new List <string>(); if (!String.IsNullOrEmpty(arguments.EndpointConfigurationType)) { serviceCommandLine.Add(String.Format(@"/endpointConfigurationType:""{0}""", arguments.EndpointConfigurationType)); } if (!String.IsNullOrEmpty(endpointName)) { serviceCommandLine.Add(String.Format(@"/endpointName:""{0}""", endpointName)); } if (!String.IsNullOrEmpty(serviceName)) { serviceCommandLine.Add(String.Format(@"/serviceName:""{0}""", serviceName)); } if (arguments.ScannedAssemblies.Count > 0) { serviceCommandLine.AddRange(arguments.ScannedAssemblies.Select(assembly => String.Format(@"/scannedAssemblies:""{0}""", assembly))); } if (arguments.OtherArgs.Any()) { serviceCommandLine.AddRange(arguments.OtherArgs); } var commandLine = String.Join(" ", serviceCommandLine); x.SetServiceCommandLine(commandLine); if (arguments.DependsOn == null) { x.DependencyOnMsmq(); } else { foreach (var dependency in arguments.DependsOn) { x.DependsOn(dependency); } } }); try { Runner.Host(cfg, args); } catch (StateMachineException exception) { var innerException = exception.InnerException; innerException.PreserveStackTrace(); throw innerException; } }
/// <summary> /// Verifies that the <see cref="MsiPayload"/> refers to a valid Windows Installer package (MSI). /// </summary> /// <param name="msiPayload">The payload to verify.</param> private void VerifyPackage(MsiPayload msiPayload) { uint error = WindowsInstaller.VerifyPackage(msiPayload.MsiPath); ExitOnError(error, $"Failed to verify package: {msiPayload.MsiPath}."); }
/// <summary> /// Plans the specified MSI payload based on its state and the requested install action. /// </summary> /// <param name="msi">The MSI package to plan.</param> /// <param name="state">The detected state of the package.</param> /// <param name="requestedAction">The requested action to perform.</param> /// <returns>The action that will be performed.</returns> private InstallAction PlanPackage(MsiPayload msi, DetectState state, InstallAction requestedAction, Version installedVersion, out IEnumerable <string> relatedProductCodes) { InstallAction plannedAction = InstallAction.None; HashSet <string> relatedProducts = new(); Log?.LogMessage($"PlanPackage: Begin, name: {msi.Name}, version: {msi.ProductVersion}, state: {state}, installed version: {installedVersion?.ToString() ?? "n/a"}, requested: {requestedAction}."); // Manifest packages should support major upgrades (both the ProductCode and ProductVersion should be different) while // workload packs should always be SxS (ProductCode and Upgrade should be different for each version). // // We cannot discount someone generating a minor update (ProductCode remains unchanged, but ProductVersion changes), // so we'll detect downgrades and minor updates. For more details, see https://docs.microsoft.com/en-us/windows/win32/msi/minor-upgrades. if (state == DetectState.Present) { if (msi.ProductVersion < installedVersion) { Log?.LogMessage($"PlanPackage: Downgrade detected, installed version: {installedVersion}, requested version: {msi.ProductVersion}."); plannedAction = InstallAction.Downgrade; state = DetectState.Superseded; } else if (msi.ProductVersion > installedVersion) { Log?.LogMessage($"PlanPackage: Minor update detected, installed version: {installedVersion}, requested version: {msi.ProductVersion}."); plannedAction = InstallAction.MinorUpdate; state = DetectState.Obsolete; } else { // If the package is installed, then we can uninstall and repair it. plannedAction = (requestedAction != InstallAction.Repair) && (requestedAction != InstallAction.Uninstall) ? InstallAction.None : requestedAction; } } else if (state == DetectState.Absent) { // If we're absent, convert repair to install or keep install. plannedAction = (requestedAction == InstallAction.Repair) ? InstallAction.Install : (requestedAction == InstallAction.Install) ? InstallAction.Install : InstallAction.None; } // At this point we know the MSI is absent so there are only three outcomes when executing the package: // 1. We'll just do a clean install if we don't find related products so we're either brand new or SxS. // 2. We'll perform a major upgrade. // 3. We'll trigger a downgrade and likely an error since most MSIs detect and block downgrades. // // We'll process the related product information to make a determination. This is similar to what the FindRelatedProducts // action does when an MSI is executed. foreach (RelatedProduct relatedProduct in msi.RelatedProducts) { foreach (string relatedProductCode in WindowsInstaller.FindRelatedProducts(relatedProduct.UpgradeCode)) { // Ignore potentially detecting ourselves. if (string.Equals(relatedProductCode, msi.ProductCode, StringComparison.OrdinalIgnoreCase)) { continue; } // Check whether the related product is installed and retrieve its version to determine // how we're related. uint error = WindowsInstaller.GetProductInfo(relatedProductCode, InstallProperty.VERSIONSTRING, out string relatedVersionValue); // Continue searching if the related product is not installed. if (error == Error.UNKNOWN_PRODUCT || error == Error.UNKNOWN_PROPERTY) { continue; } ExitOnError(error, $"PlanPackage: Failed to retrieve version for related product: ProductCode: {relatedProductCode}."); // Parse the version, but don't try to catch any errors. If the version is invalid we want to fail // because we can't compare invalid versions to see whether it's excluded by the VersionMin and VersionMax // columns from the Upgrade table. Version relatedVersion = Version.Parse(relatedVersionValue); if (relatedProduct.ExcludesMinVersion(relatedVersion) || relatedProduct.ExcludesMaxVersion(relatedVersion)) { continue; } // Check if the related product contains a matching language code (LCID). If we don't have any languages, // all languages are detectable as related and we can ignore the msidbUpgradeAttributesLanguagesExclusive flag. if (relatedProduct.Languages.Any()) { string relatedLanguage = "0"; error = WindowsInstaller.GetProductInfo(relatedProductCode, InstallProperty.LANGUAGE, out relatedLanguage); if (int.TryParse(relatedLanguage, out int lcid)) { if (relatedProduct.ExcludesLanguage(lcid)) { continue; } } else { Log?.LogMessage($"PlanPackage: Failed to read Language property for related product, ProductCode: {relatedProductCode}. The related product will be skipped."); continue; } } relatedProducts.Add(relatedProductCode); plannedAction = InstallAction.MajorUpgrade; if (relatedProduct.Attributes.HasFlag(UpgradeAttributes.OnlyDetect) && (state == DetectState.Absent)) { // If we're not installed, but detect-only related, it's very likely that // that we'd trigger a downgrade launch condition. We can't know for sure, but // generally that's the most common use for detect-only entries. plannedAction = InstallAction.Downgrade; } Log?.LogMessage($"PlanPackage: Detected related product, ProductCode: {relatedProductCode}, version: {relatedVersion}, attributes: {relatedProduct.Attributes}, planned action: {plannedAction}."); } } Log?.LogMessage($"PlanPackage: Completed, name: {msi.Name}, version: {msi.ProductVersion}, state: {state}, installed version: {installedVersion?.ToString() ?? "n/a"}, requested: {requestedAction}, planned: {plannedAction}."); relatedProductCodes = relatedProducts.Select(p => p); return(plannedAction); }
static void Main(string[] args) { Parser.Args commandLineArguments = Parser.ParseArgs(args); var arguments = new HostArguments(commandLineArguments); if (arguments.Help != null) { DisplayHelpContent(); return; } var endpointConfigurationType = GetEndpointConfigurationType(arguments); if (endpointConfigurationType == null) { if (arguments.InstallInfrastructure == null) { throw new InvalidOperationException("No endpoint configuration found in scanned assemblies. " + "This usually happens when NServiceBus fails to load your assembly containing IConfigureThisEndpoint." + " Try specifying the type explicitly in the NServiceBus.Host.exe.config using the appsetting key: EndpointConfigurationType, " + "Scanned path: " + AppDomain.CurrentDomain.BaseDirectory); } Console.WriteLine("Running infrastructure installers and exiting (ignoring other command line parameters if exist)."); InstallInfrastructure(); return; } AssertThatEndpointConfigurationTypeHasDefaultConstructor(endpointConfigurationType); string endpointConfigurationFile = GetEndpointConfigurationFile(endpointConfigurationType); var endpointName = GetEndpointName(endpointConfigurationType, arguments); var endpointVersion = GetEndpointVersion(endpointConfigurationType); var serviceName = endpointName; if (arguments.ServiceName != null) { serviceName = arguments.ServiceName.Value; } var displayName = serviceName + "-" + endpointVersion; if (arguments.SideBySide != null) { serviceName += "-" + endpointVersion; displayName += " (SideBySide)"; } //add the endpoint name so that the new appdomain can get it args = args.Concat(new[] { endpointName }).ToArray(); AppDomain.CurrentDomain.SetupInformation.AppDomainInitializerArguments = args; if ((commandLineArguments.Install) || (arguments.InstallInfrastructure != null)) { WindowsInstaller.Install(args, endpointConfigurationType, endpointName, endpointConfigurationFile, commandLineArguments.Install, arguments.InstallInfrastructure != null); } IRunConfiguration cfg = RunnerConfigurator.New(x => { x.ConfigureServiceInIsolation <WindowsHost>(endpointConfigurationType.AssemblyQualifiedName, c => { c.ConfigurationFile(endpointConfigurationFile); c.CommandLineArguments(args, () => SetHostServiceLocatorArgs); c.WhenStarted(service => service.Start()); c.WhenStopped(service => service.Stop()); c.CreateServiceLocator(() => new HostServiceLocator()); }); if (arguments.Username != null && arguments.Password != null) { x.RunAs(arguments.Username.Value, arguments.Password.Value); } else { x.RunAsLocalSystem(); } if (arguments.StartManually != null) { x.DoNotStartAutomatically(); } x.SetDisplayName(arguments.DisplayName != null ? arguments.DisplayName.Value : displayName); x.SetServiceName(serviceName); x.SetDescription(arguments.Description != null ? arguments.Description.Value : "NServiceBus Message Endpoint Host Service for " + displayName); var serviceCommandLine = commandLineArguments.CustomArguments.AsCommandLine(); serviceCommandLine += " /serviceName:\"" + serviceName + "\""; serviceCommandLine += " /endpointName:\"" + endpointName + "\""; x.SetServiceCommandLine(serviceCommandLine); if (arguments.DependsOn == null) { x.DependencyOnMsmq(); } else { foreach (var dependency in arguments.DependsOn.Value.Split(',')) { x.DependsOn(dependency); } } }); Runner.Host(cfg, args); }
public void QueryProductStateReturnsAnError(string productCode, InstallState expectedState) { InstallState state = WindowsInstaller.QueryProduct(productCode); Assert.Equal(state, expectedState); }
public void InstallProductReturnsAnError(string productCode, string property, uint expectedError) { uint error = WindowsInstaller.GetProductInfo(productCode, property, out string propertyValue); Assert.Equal(error, expectedError); }
static void Main(string[] args) { Parser.Args commandLineArguments = Parser.ParseArgs(args); var arguments = new HostArguments(commandLineArguments); if (arguments.Help != null) { DisplayHelpContent(); return; } var endpointConfigurationType = GetEndpointConfigurationType(arguments); AssertThatEndpointConfigurationTypeHasDefaultConstructor(endpointConfigurationType); string endpointConfigurationFile = GetEndpointConfigurationFile(endpointConfigurationType); var endpointName = GetEndpointName(endpointConfigurationType); var endpointVersion = GetEndpointVersion(endpointConfigurationType); if (arguments.ServiceName != null) { endpointName = arguments.ServiceName.Value; } var serviceName = endpointName; var displayName = serviceName + "-" + endpointVersion; //add the endpoint name so that the new appdomain can get it args = args.Concat(new[] { endpointName }).ToArray(); AppDomain.CurrentDomain.SetupInformation.AppDomainInitializerArguments = args; if (commandLineArguments.Install) { WindowsInstaller.Install(args, endpointConfigurationType, endpointName, endpointConfigurationFile); } IRunConfiguration cfg = RunnerConfigurator.New(x => { x.ConfigureServiceInIsolation <WindowsHost>(endpointConfigurationType.AssemblyQualifiedName, c => { c.ConfigurationFile(endpointConfigurationFile); c.CommandLineArguments(args, () => SetHostServiceLocatorArgs); c.WhenStarted(service => service.Start()); c.WhenStopped(service => service.Stop()); c.CreateServiceLocator(() => new HostServiceLocator()); }); if (arguments.Username != null && arguments.Password != null) { x.RunAs(arguments.Username.Value, arguments.Password.Value); } else { x.RunAsLocalSystem(); } if (arguments.StartManually != null) { x.DoNotStartAutomatically(); } x.SetDisplayName(arguments.DisplayName != null ? arguments.DisplayName.Value : displayName); x.SetServiceName(serviceName); x.SetDescription(arguments.Description != null ? arguments.Description.Value : "NServiceBus Message Endpoint Host Service for " + displayName); var serviceCommandLine = commandLineArguments.CustomArguments.AsCommandLine(); serviceCommandLine += " /serviceName:\"" + serviceName + "\""; x.SetServiceCommandLine(serviceCommandLine); if (arguments.DependsOn == null) { x.DependencyOnMsmq(); } else { foreach (var dependency in arguments.DependsOn.Value.Split(',')) { x.DependsOn(dependency); } } }); Runner.Host(cfg, args); }