public static EarlyBoundGeneratorConfig Load(string filePath)
        {
            try
            {
                filePath = Path.Combine(filePath, "DLaB.EarlyBoundGenerator.Settings.xml");
                if (!File.Exists(filePath))
                {
                    var config = GetDefault();
                    config._filePath = filePath;
                    return config;
                }

                var serializer = new XmlSerializer(typeof (POCO.Config));
                POCO.Config poco;
                using (var fs = new FileStream(filePath, FileMode.Open))
                {
                    poco = (POCO.Config) serializer.Deserialize(fs);
                    fs.Close();
                }
                var settings = new EarlyBoundGeneratorConfig(poco, filePath);
                return settings;
            }
            catch (Exception ex)
            {
                throw new Exception("An error occured attempting to load Xml configuration: " + filePath, ex);
            }
        }
        private static void UpdateObsoleteSettings(POCO.Config poco, POCO.ExtensionConfig pocoConfig, EarlyBoundGeneratorConfig @default)
        {
            if (new Version(poco.Version) < new Version("1.2016.6.1"))
            {
                // Storing of UnmappedProperties and EntityAttributeSpecified Names switched from Key,Value1,Value2|Key,Value1,Value2 to Key:Value1,Value2|Key:Value1,Value2
                // Also convert from a List to a HashSet
                pocoConfig.EntityAttributeSpecifiedNames = ConvertNonColonDelimitedDictionaryListToDictionaryHash(pocoConfig.EntityAttributeSpecifiedNames);
                pocoConfig.UnmappedProperties            = ConvertNonColonDelimitedDictionaryListToDictionaryHash(pocoConfig.UnmappedProperties);
            }

            if (new Version(poco.Version) < new Version("1.2018.9.12"))
            {
                // Update the OptionSet codecustomization Argument Setting to use the new Generic Code Customziation Service
                var oldValue = poco.ExtensionArguments.FirstOrDefault(
                    a => a.SettingType == CreationType.OptionSets &&
                    a.Name == "codecustomization");
                var newValue = @default.ExtensionArguments.FirstOrDefault(
                    a => a.SettingType == CreationType.OptionSets &&
                    a.Name == "codecustomization");
                if (oldValue != null &&
                    newValue != null)
                {
                    poco.ExtensionArguments.Remove(oldValue);
                    poco.ExtensionArguments.Add(newValue);
                }
            }
        }
        private string GetConfigArguments(EarlyBoundGeneratorConfig earlyBoundGeneratorConfig, CreationType type)
        {
            var sb = new StringBuilder();
            if (!earlyBoundGeneratorConfig.UseConnectionString)
            {
                sb.AppendFormat("/url:\"{0}\" ", earlyBoundGeneratorConfig.Url);
            }

            foreach (var argument in earlyBoundGeneratorConfig.CommandLineArguments.Where(a => a.SettingType == CreationType.All || a.SettingType == type))
            {
                var value = argument.Value;
                if (argument.Name == "out")
                {
                    value = GetOutputFilePath(earlyBoundGeneratorConfig, type);
                }
                if (argument.Value == null)
                {
                    sb.AppendFormat("/{0} ", argument.Name);
                }
                else
                {
                    sb.AppendFormat("/{0}:\"{1}\" ", argument.Name, value);
                }
            }

            if (!string.IsNullOrWhiteSpace(earlyBoundGeneratorConfig.Password))
            {
                if (EarlyBoundGeneratorConfig.UseConnectionString)
                {
                    // Fix for https://github.com/daryllabar/DLaB.Xrm.XrmToolBoxTools/issues/14 - Problem with CRM 2016 on premises with ADFS
                    // CrmSvcUtil.exe /out:entitie.cs / connectionstring:"Url=https://serverName.domain.com:444/orgName;Domain=myDomain;UserName=username;Password=*****"
                    // And this command doesn't work :
                    // CrmSvcUtil.exe /out:entitie.cs /url:"https://serverName.domain.com:444/orgName" / domain:"myDomain" / username:"******" / password:"******"

                    var domain = string.Empty;
                    if (!string.IsNullOrWhiteSpace(earlyBoundGeneratorConfig.Domain))
                    {
                        domain = "Domain=" +earlyBoundGeneratorConfig.Domain + ";";
                    }
                    var password = earlyBoundGeneratorConfig.Password.Replace("\"", "^\"").Replace("&", "^&");  // Handle Double Quotes and &s???
                    var builder = new System.Data.Common.DbConnectionStringBuilder
                    {
                        {"A", $"Url={earlyBoundGeneratorConfig.Url};{domain}UserName={earlyBoundGeneratorConfig.UserName};Password={password}"}
                    };
                    
                    sb.AppendFormat("/connectionstring:{0} ", builder.ConnectionString.Substring(2)); // Replace "A=" with "/connectionstring:"
                }
                else
                {
                    sb.AppendFormat("/username:\"{0}\" ", earlyBoundGeneratorConfig.UserName);
                    sb.AppendFormat("/password:\"{0}\" ", earlyBoundGeneratorConfig.Password);

                    // Add Login Info
                    if (!earlyBoundGeneratorConfig.UseCrmOnline && !string.IsNullOrWhiteSpace(earlyBoundGeneratorConfig.Domain))
                    {
                        sb.AppendFormat("/domain:\"{0}\" ", earlyBoundGeneratorConfig.Domain);
                    }
                }
            }

            return sb.ToString();
        }
        private void RemoveObsoleteValues(POCO.Config poco, EarlyBoundGeneratorConfig @default)
        {
            if (CrmSvcUtilRelativePath == @"CrmSvcUtil Ref\crmsvcutil.exe")
            {
                // 5.14.2015 XTB changed to use the Plugins Directory, but then MEF changed Paths to be realtive to Dll. 
                CrmSvcUtilRelativePath = @default.CrmSvcUtilRelativePath;
            }
            foreach (var value in poco.ExtensionArguments.Where(a => string.Equals(a.Value, "DLaB.CrmSvcUtilExtensions.Entity.OverridePropertyNames,DLaB.CrmSvcUtilExtensions", StringComparison.InvariantCultureIgnoreCase)).ToList())
            {
                // Pre 2.13.2016, this was the default value.  Replaced with a single naming service that both Entities and OptionSets can use
                poco.ExtensionArguments.Remove(value);
            }

            // Pre 2.13.2016, this was the default value.  Not Needed Anymore
            var old = "OpportunityProduct.OpportunityStateCode,opportunity_statuscode|" +
                      "OpportunityProduct.PricingErrorCode,qooi_pricingerrorcode|" +
                      "ResourceGroup.GroupTypeCode,constraintbasedgroup_grouptypecode";
            if (string.Equals(poco.ExtensionConfig.PropertyEnumMappings, old, StringComparison.InvariantCultureIgnoreCase) || string.Equals(poco.ExtensionConfig.PropertyEnumMappings, old + "|", StringComparison.InvariantCultureIgnoreCase))
            {
                poco.ExtensionConfig.PropertyEnumMappings = string.Empty;
            }
        }
 public Logic(EarlyBoundGeneratorConfig earlyBoundGeneratorConfig)
 {
     EarlyBoundGeneratorConfig = earlyBoundGeneratorConfig;
 }
        private void UpdateCrmSvcUtilConfig(EarlyBoundGeneratorConfig earlyBoundGeneratorConfig)
        {
            lock (_updateAppConfigToken)
            {
                if (_configUpdated) { return; }
                //load custom config file
                Configuration file;

                string filePath = Path.GetFullPath(earlyBoundGeneratorConfig.CrmSvcUtilPath) + ".config";
                var map = new ExeConfigurationFileMap { ExeConfigFilename = filePath };
                try
                {
                    file = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
                }
                catch (ConfigurationErrorsException ex)
                {
                    if (ex.BareMessage == "Root element is missing.")
                    {
                        File.Delete(filePath);
                        UpdateCrmSvcUtilConfig(earlyBoundGeneratorConfig);
                        return;
                    }
                    throw;
                }

                var extensions = earlyBoundGeneratorConfig.ExtensionConfig;
                if (UpdateConfigAppSetting(file, "ActionCommandLineText", extensions.ActionCommandLineText, true) |
                    UpdateConfigAppSetting(file, "ActionsToSkip", extensions.ActionsToSkip) |
                    UpdateConfigAppSetting(file, "AddDebuggerNonUserCode", extensions.AddDebuggerNonUserCode.ToString()) |
                    UpdateConfigAppSetting(file, "AddNewFilesToProject", extensions.AddNewFilesToProject.ToString()) |
                    UpdateConfigAppSetting(file, "CreateOneFilePerAction", extensions.CreateOneFilePerAction.ToString()) |
                    UpdateConfigAppSetting(file, "CreateOneFilePerEntity", extensions.CreateOneFilePerEntity.ToString()) |
                    UpdateConfigAppSetting(file, "CreateOneFilePerOptionSet", extensions.CreateOneFilePerOptionSet.ToString()) |
                    UpdateConfigAppSetting(file, "EntityAttributeSpecifiedNames", extensions.EntityAttributeSpecifiedNames) |
                    UpdateConfigAppSetting(file, "EntityCommandLineText", extensions.EntityCommandLineText, true) |
                    UpdateConfigAppSetting(file, "EntitiesToSkip", extensions.EntitiesToSkip) |
                    UpdateConfigAppSetting(file, "GenerateAttributeNameConsts", extensions.GenerateAttributeNameConsts.ToString()) |
                    UpdateConfigAppSetting(file, "GenerateAnonymousTypeConstructor", extensions.GenerateAnonymousTypeConstructor.ToString()) |
                    UpdateConfigAppSetting(file, "GenerateEntityRelationships", extensions.GenerateEntityRelationships.ToString()) |
                    UpdateConfigAppSetting(file, "GenerateEnumProperties", extensions.GenerateEnumProperties.ToString()) |
                    UpdateConfigAppSetting(file, "InvalidCSharpNamePrefix", extensions.InvalidCSharpNamePrefix) |
                    UpdateConfigAppSetting(file, "MakeReadonlyFieldsEditable", extensions.MakeReadonlyFieldsEditable.ToString()) |
                    UpdateConfigAppSetting(file, "LocalOptionSetFormat", extensions.LocalOptionSetFormat) |
                    UpdateConfigAppSetting(file, "OptionSetsToSkip", extensions.OptionSetsToSkip) |
                    UpdateConfigAppSetting(file, "OptionSetCommandLineText", extensions.OptionSetCommandLineText, true) |
                    UpdateConfigAppSetting(file, "PropertyEnumMappings", extensions.PropertyEnumMappings) |
                    UpdateConfigAppSetting(file, "RemoveRuntimeVersionComment", extensions.RemoveRuntimeVersionComment.ToString()) |
                    UpdateConfigAppSetting(file, "UseDeprecatedOptionSetNaming", extensions.UseDeprecatedOptionSetNaming.ToString()) |
                    UpdateConfigAppSetting(file, "UnmappedProperties", extensions.UnmappedProperties) |
                    UpdateConfigAppSetting(file, "UseTfsToCheckoutFiles", extensions.UseTfsToCheckoutFiles.ToString()) |
                    UpdateConfigAppSetting(file, "UseXrmClient", extensions.UseXrmClient.ToString()))

                {
                    file.Save(ConfigurationSaveMode.Minimal);
                }
                _configUpdated = true;
            }
        }
 private static string GetSafeArgs(EarlyBoundGeneratorConfig earlyBoundGeneratorConfig, Process p)
 {
     var args = p.StartInfo.Arguments;
     if (earlyBoundGeneratorConfig.MaskPassword && !string.IsNullOrWhiteSpace(earlyBoundGeneratorConfig.Password))
     {
         args = p.StartInfo.Arguments.Replace(earlyBoundGeneratorConfig.Password, new string('*', earlyBoundGeneratorConfig.Password.Length));
     }
     return args;
 }
        private string GetOutputFilePath(EarlyBoundGeneratorConfig earlyBoundGeneratorConfig, CreationType creationType)
        {
            // ReSharper disable once AssignNullToNotNullAttribute
            var filePath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), EarlyBoundGeneratorConfig.GetSettingValue(creationType, EarlyBoundGeneratorConfig.UserArgumentNames.Out));

            if (creationType == CreationType.Actions && earlyBoundGeneratorConfig.ExtensionConfig.CreateOneFilePerAction)
            {
                filePath = Path.Combine(filePath, "Actions.cs");
            }
            else if (creationType == CreationType.Entities && earlyBoundGeneratorConfig.ExtensionConfig.CreateOneFilePerEntity)
            {
                var entities = earlyBoundGeneratorConfig.ServiceContextName;

                if (string.IsNullOrWhiteSpace(entities))
                {
                    entities = "Entities";
                }

                filePath = Path.Combine(filePath, entities + ".cs");
            }
            else if (creationType == CreationType.OptionSets && earlyBoundGeneratorConfig.ExtensionConfig.CreateOneFilePerOptionSet)
            {
                filePath = Path.Combine(filePath, "OptionSets.cs");
            }

            return filePath;
        }
        private static void UpdateObsoleteSettings(POCO.Config poco, POCO.ExtensionConfig pocoConfig, EarlyBoundGeneratorConfig @default)
        {
            var pocoVersion = new Version(poco.Version);

            if (pocoVersion < new Version("1.2016.6.1"))
            {
                // Storing of UnmappedProperties and EntityAttributeSpecified Names switched from Key,Value1,Value2|Key,Value1,Value2 to Key:Value1,Value2|Key:Value1,Value2
                // Also convert from a List to a HashSet
                pocoConfig.EntityAttributeSpecifiedNames = ConvertNonColonDelimitedDictionaryListToDictionaryHash(pocoConfig.EntityAttributeSpecifiedNames);
                pocoConfig.UnmappedProperties            = ConvertNonColonDelimitedDictionaryListToDictionaryHash(pocoConfig.UnmappedProperties);
            }

            if (pocoVersion < new Version("1.2018.9.12"))
            {
                // Update the OptionSet codecustomization Argument Setting to use the new Generic Code Customization Service
                var oldValue = poco.ExtensionArguments.FirstOrDefault(
                    a => a.SettingType == CreationType.OptionSets &&
                    a.Name == "codecustomization");
                var newValue = @default.ExtensionArguments.FirstOrDefault(
                    a => a.SettingType == CreationType.OptionSets &&
                    a.Name == "codecustomization");
                if (oldValue != null &&
                    newValue != null)
                {
                    poco.ExtensionArguments.Remove(oldValue);
                    poco.ExtensionArguments.Add(newValue);
                }
            }

            if (pocoVersion < new Version("1.2020.3.23"))
            {
                // Added new option to overwrite Option Set properties.  This is the desired default now, but don't break old generation settings.
                if (poco.ExtensionConfig.ReplaceOptionSetPropertiesWithEnum == null)
                {
                    poco.ExtensionConfig.ReplaceOptionSetPropertiesWithEnum = false;
                }
            }

            if (pocoVersion < new Version("1.2020.10.1"))
            {
                // Issue #254 add invalid actions to blacklist.
                var invalidBlacklistItems = "RetrieveAppSettingList|RetrieveAppSetting|SaveAppSetting|msdyn_GetSIFeatureConfiguration".ToLower();
                if (string.IsNullOrWhiteSpace(poco.ExtensionConfig.ActionsToSkip))
                {
                    poco.ExtensionConfig.ActionsToSkip = invalidBlacklistItems;
                }
                else
                {
                    poco.ExtensionConfig.ActionsToSkip += "|" + invalidBlacklistItems;
                }
            }

            if (pocoVersion < new Version("1.2020.12.18"))
            {
                // 12.18.2020 introduced Valueless parameters, but GenerateActions existed before as a null, need a boolean value to determine if it should be included
                var generateActions = poco.UserArguments.FirstOrDefault(a => a.Name == UserArgumentNames.GenerateActions && a.Value == null);
                if (generateActions != null)
                {
                    generateActions.Value     = "true";
                    generateActions.Valueless = true;
                }
            }
        }