diff --git a/ViVeTool/ArgumentBlock.cs b/ViVeTool/ArgumentBlock.cs index 6654963..c11b97c 100644 --- a/ViVeTool/ArgumentBlock.cs +++ b/ViVeTool/ArgumentBlock.cs @@ -65,11 +65,10 @@ internal static void Initialize(string[] args, ArgumentBlockFlags flags) for (int i = 1; i < args.Length && flags != 0; i++) { var firstSc = args[i].IndexOf(':'); - //if (firstSc == -1) continue; var hasValue = firstSc != -1; var lower = args[i].ToLowerInvariant(); var key = hasValue ? lower.Substring(0, firstSc) : lower; - var value = hasValue ? args[i].Substring(firstSc + 1) : null; + var value = hasValue ? args[i].Substring(firstSc + 1) : string.Empty; if (flags.HasFlag(ArgumentBlockFlags.Store) && key == "/store") { if (Enum.TryParse(value, true, out FeatureConfigurationTypeEx parsedStore)) @@ -142,7 +141,8 @@ internal static void Initialize(string[] args, ArgumentBlockFlags flags) } else if (flags.HasFlag(ArgumentBlockFlags.Priority) && key == "/priority") { - if (!Enum.TryParse(value, true, out RTL_FEATURE_CONFIGURATION_PRIORITY parsedPriority)) + if (!Enum.TryParse(value, true, out RTL_FEATURE_CONFIGURATION_PRIORITY parsedPriority) || + ((int)parsedPriority < 1 || (int)parsedPriority > 14)) { ConsoleEx.WriteErrorLine(Properties.Resources.InvalidEnumSpec, value, "Priority"); HelpMode = true; diff --git a/ViVeTool/FeatureNaming.cs b/ViVeTool/FeatureNaming.cs index 7300bcc..e7423c2 100644 --- a/ViVeTool/FeatureNaming.cs +++ b/ViVeTool/FeatureNaming.cs @@ -25,13 +25,14 @@ namespace Albacore.ViVeTool internal class FeatureNaming { internal const string DictFileName = "FeatureDictionary.pfs"; + internal static string DictFilePath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), DictFileName); internal static List FindIdsForNames(IEnumerable featureNames) { - if (!File.Exists(DictFileName)) + if (!File.Exists(DictFilePath)) return null; var result = new List(); var namesCommas = featureNames.Select(x => x.ToLowerInvariant() + ",").ToList(); - using (StreamReader reader = new StreamReader(File.OpenRead(DictFileName))) + using (StreamReader reader = new StreamReader(File.OpenRead(DictFilePath))) { while (!reader.EndOfStream) { @@ -55,10 +56,10 @@ internal static List FindIdsForNames(IEnumerable featureNames) internal static Dictionary FindNamesForFeatures(IEnumerable featureIDs) { var result = new Dictionary(); - if (!File.Exists(DictFileName)) + if (!File.Exists(DictFilePath)) return null; var idsCommas = featureIDs.Select(x => "," + x.ToString()).ToList(); - using (StreamReader reader = new StreamReader(File.OpenRead(DictFileName))) + using (StreamReader reader = new StreamReader(File.OpenRead(DictFilePath))) { while (!reader.EndOfStream) { diff --git a/ViVeTool/Program.cs b/ViVeTool/Program.cs index baafde4..2a9c903 100644 --- a/ViVeTool/Program.cs +++ b/ViVeTool/Program.cs @@ -120,6 +120,9 @@ static void ProcessArgs(string[] args) ArgumentBlock.Initialize(args, 0); HandleFixLKG(); break; + case "/fixpriority": + HandleFixPriority(); + break; case "/appupdate": HandleAppUpdate(); break; @@ -183,7 +186,8 @@ static void HandleQuery() foreach (var config in retrievedConfigs) { string name = null; - try { name = namesAll[config.FeatureId]; } catch { } + if (namesAll != null) + try { name = namesAll[config.FeatureId]; } catch { } PrintFeatureConfig(config, name); } } @@ -199,7 +203,8 @@ static void HandleQuery() if (config != null) { string name = null; - try { name = namesSpecific[id]; } catch { } + if (namesSpecific != null) + try { name = namesSpecific[id]; } catch { } PrintFeatureConfig(config.Value, name); } else @@ -234,7 +239,7 @@ static void HandleSet(RTL_FEATURE_ENABLED_STATE state) FeatureId = ArgumentBlock.IdList[i], EnabledState = state, EnabledStateOptions = fcp.EnabledStateOptions, - Priority = fcp.Priority ?? RTL_FEATURE_CONFIGURATION_PRIORITY.Service, + Priority = fcp.Priority ?? RTL_FEATURE_CONFIGURATION_PRIORITY.User, Variant = fcp.Variant, VariantPayloadKind = fcp.VariantPayloadKind, VariantPayload = fcp.VariantPayload, @@ -315,7 +320,8 @@ static void HandleQuerySubs() foreach (var sub in retrievedSubs) { string name = null; - try { name = names[sub.FeatureId]; } catch { } + if (names != null) + try { name = names[sub.FeatureId]; } catch { } PrintSubscription(sub, name); } } @@ -533,6 +539,14 @@ static void HandleFixLKG() Console.WriteLine(Properties.Resources.FixLKGNotNeeded); } + static void HandleFixPriority() + { + var success = FixPriorityInternal(RTL_FEATURE_CONFIGURATION_TYPE.Runtime); + if (!success) + return; + FixPriorityInternal(RTL_FEATURE_CONFIGURATION_TYPE.Boot); + } + static void HandleAppUpdate() { Console.WriteLine(Properties.Resources.CheckingAppUpdates); @@ -605,7 +619,7 @@ static void FindResettablesInternal(RTL_FEATURE_CONFIGURATION_TYPE type, bool fu } } - static void FinalizeSet(RTL_FEATURE_CONFIGURATION_UPDATE[] updates, bool isReset) + static bool FinalizeSet(RTL_FEATURE_CONFIGURATION_UPDATE[] updates, bool isReset) { var useBothStores = ArgumentBlock.ShouldUseBothStores; if (useBothStores || ArgumentBlock.Store == FeatureConfigurationTypeEx.Runtime) @@ -615,7 +629,7 @@ static void FinalizeSet(RTL_FEATURE_CONFIGURATION_UPDATE[] updates, bool isReset { ConsoleEx.WriteErrorLine(isReset ? Properties.Resources.ResetRuntimeFailed : Properties.Resources.SetRuntimeFailed, GetHumanErrorDescription(result)); - return; + return false; } } if (useBothStores || ArgumentBlock.Store == FeatureConfigurationTypeEx.Boot) @@ -625,13 +639,14 @@ static void FinalizeSet(RTL_FEATURE_CONFIGURATION_UPDATE[] updates, bool isReset { ConsoleEx.WriteErrorLine(isReset ? Properties.Resources.ResetBootFailed : Properties.Resources.SetBootFailed, GetHumanErrorDescription(result)); - return; + return false; } UpdateLKGStatus(BSD_FEATURE_CONFIGURATION_STATE.BootPending); } Console.WriteLine(isReset ? Properties.Resources.ResetSuccess : Properties.Resources.SetSuccess); + return true; } static void UpdateLKGStatus(BSD_FEATURE_CONFIGURATION_STATE newStatus) @@ -708,6 +723,53 @@ static RTL_FEATURE_CONFIGURATION_UPDATE[] ConvertConfigsToUpdates(List x.Priority == RTL_FEATURE_CONFIGURATION_PRIORITY.Service && !x.IsWexpConfiguration); + if (!configsToFix.Any()) + return null; + var priorityFixUpdates = new RTL_FEATURE_CONFIGURATION_UPDATE[configsToFix.Count() * 2]; + var updatesCreated = 0; + foreach (var cfg in configsToFix) + { + priorityFixUpdates[updatesCreated] = new RTL_FEATURE_CONFIGURATION_UPDATE() + { + FeatureId = cfg.FeatureId, + Priority = cfg.Priority, + Operation = RTL_FEATURE_CONFIGURATION_OPERATION.ResetState + }; + priorityFixUpdates[updatesCreated + 1] = new RTL_FEATURE_CONFIGURATION_UPDATE() + { + FeatureId = cfg.FeatureId, + Priority = RTL_FEATURE_CONFIGURATION_PRIORITY.User, + EnabledState = cfg.EnabledState, + Variant = cfg.Variant, + VariantPayloadKind = cfg.VariantPayloadKind, + VariantPayload = cfg.VariantPayload, + Operation = RTL_FEATURE_CONFIGURATION_OPERATION.FeatureState | RTL_FEATURE_CONFIGURATION_OPERATION.VariantState + }; + updatesCreated += 2; + } + return priorityFixUpdates; + } + static void CommandMigrationInfoTip(string oldCommand, string newCommand) { ConsoleEx.WriteWarnLine(Properties.Resources.CommandMigrationNote, oldCommand, newCommand); @@ -735,7 +797,10 @@ static void PrintFeatureConfig(RTL_FEATURE_CONFIGURATION config, string name = n Console.Write(" ({0})", name); Console.WriteLine(); Console.ForegroundColor = defaultFg; - Console.WriteLine(Properties.Resources.FeatureDisplay_Priority, config.Priority, (uint)config.Priority); + if (Enum.IsDefined(typeof(RTL_FEATURE_CONFIGURATION_PRIORITY), config.Priority)) + Console.WriteLine(Properties.Resources.FeatureDisplay_Priority + " ({1})", config.Priority, (uint)config.Priority); + else + Console.WriteLine(Properties.Resources.FeatureDisplay_Priority, config.Priority, (uint)config.Priority); Console.WriteLine(Properties.Resources.FeatureDisplay_State, config.EnabledState, (uint)config.EnabledState); Console.WriteLine(Properties.Resources.FeatureDisplay_Type, config.IsWexpConfiguration ? Properties.Resources.FeatureType_Experiment : Properties.Resources.FeatureType_Override, diff --git a/ViVeTool/Properties/AssemblyInfo.cs b/ViVeTool/Properties/AssemblyInfo.cs index 5642298..32c6c1e 100644 --- a/ViVeTool/Properties/AssemblyInfo.cs +++ b/ViVeTool/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.3.1.0")] -[assembly: AssemblyFileVersion("0.3.1.0")] +[assembly: AssemblyVersion("0.3.2.0")] +[assembly: AssemblyFileVersion("0.3.2.0")] diff --git a/ViVeTool/Properties/Resources.Designer.cs b/ViVeTool/Properties/Resources.Designer.cs index f6df95d..387d9b6 100644 --- a/ViVeTool/Properties/Resources.Designer.cs +++ b/ViVeTool/Properties/Resources.Designer.cs @@ -70,7 +70,7 @@ internal class Resources { } /// - /// Looks up a localized string similar to ViVeTool v0.3.1 - Windows feature configuration tool + /// Looks up a localized string similar to ViVeTool v0.3.2 - Windows feature configuration tool ///. /// internal static string Branding { @@ -181,7 +181,7 @@ internal class Resources { } /// - /// Looks up a localized string similar to Priority : {0} ({1}). + /// Looks up a localized string similar to Priority : {0}. /// internal static string FeatureDisplay_Priority { get { @@ -252,6 +252,24 @@ internal class Resources { } } + /// + /// Looks up a localized string similar to No configurations in this store need to be moved. + /// + internal static string FixPriorityNotNeeded { + get { + return ResourceManager.GetString("FixPriorityNotNeeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Moving Override type {0} configurations from Service to User priority.... + /// + internal static string FixPriorityProcessing { + get { + return ResourceManager.GetString("FixPriorityProcessing", resourceCulture); + } + } + /// /// Looks up a localized string similar to Full reset canceled. /// @@ -413,14 +431,14 @@ internal class Resources { /// /// Looks up a localized string similar to Syntax: /// /reset {{/id:<comma delimited feature IDs> | /name:<comma delimited feature names>}} - /// [/priority:<enrollment | service | user | userpolicy | test>] [/store:<both | runtime | boot>] + /// [/priority:{{<enrollment | service | user | userpolicy | test> | <1-14>}}] [/store:<both | runtime | boot>] /// ///Features can be specified using both their IDs and names, mixing and matching is allowed. /// ///By default the features you've chosen will have their configuration overrides erased from ///all priorities and both stores. Specifying a priority will limit the scope of the reset. /// - ///ImageDefault (0) and ImageOverride (15) [rest of string was truncated]";. + ///ImageDefault (0) and Image [rest of string was truncated]";. /// internal static string Help_Reset { get { @@ -432,14 +450,13 @@ internal class Resources { /// Looks up a localized string similar to Syntax: /// {0} {{/id:<comma delimited feature IDs> | /name:<comma delimited feature names>}} [/variant:<0-63>] /// [/variantpayloadkind:<none | resident | external>] [/variantpayload:<0-4294967295>] [/experiment] - /// [/priority:<enrollment | service | user | userpolicy | test>] [/store:<both | runtime | boot>] + /// [/priority:{{<enrollment | service | user | userpolicy | test> | <1-14>}}] [/store:<both | runtime | boot>] /// ///The parameters in square brackets don't need to be specified and will use these defaults: /// Variant : 0 /// VariantPayloadKind: None /// VariantPayload : 0 - /// Experiment : false - /// [rest of string was truncated]";. + /// Experiment [rest of string was truncated]";. /// internal static string Help_Set { get { diff --git a/ViVeTool/Properties/Resources.resx b/ViVeTool/Properties/Resources.resx index a5086f8..544a78f 100644 --- a/ViVeTool/Properties/Resources.resx +++ b/ViVeTool/Properties/Resources.resx @@ -121,7 +121,7 @@ Boot store changes require a reboot to fully take effect, please do so if a configuration appears to be missing - ViVeTool v0.3.1 - Windows feature configuration tool + ViVeTool v0.3.2 - Windows feature configuration tool @@ -160,7 +160,7 @@ Arguments are now position independent and clearly labeled, ambiguous strings of PayloadKind : {0} ({1}) - Priority : {0} ({1}) + Priority : {0} State : {0} ({1}) @@ -183,6 +183,12 @@ Arguments are now position independent and clearly labeled, ambiguous strings of 'Last Known Good' rollback system data has been fixed successfully + + No configurations in this store need to be moved + + + Moving Override type {0} configurations from Service to User priority... + Full reset canceled @@ -205,6 +211,7 @@ Arguments are now position independent and clearly labeled, ambiguous strings of /import Imports custom feature configurations /lkgstatus Prints the current 'Last Known Good' rollback system status /fixlkg Fixes 'Last Known Good' rollback system corruption + /fixpriority Moves Override type configurations from Service to User priority* /appupdate Checks for a new version of ViVeTool* /dictupdate Checks for a new version of the feature name dictionary* @@ -305,7 +312,7 @@ Examples: Syntax: /reset {{/id:<comma delimited feature IDs> | /name:<comma delimited feature names>}} - [/priority:<enrollment | service | user | userpolicy | test>] [/store:<both | runtime | boot>] + [/priority:{{<enrollment | service | user | userpolicy | test> | <1-14>}}] [/store:<both | runtime | boot>] Features can be specified using both their IDs and names, mixing and matching is allowed. @@ -323,20 +330,21 @@ Examples: Syntax: {0} {{/id:<comma delimited feature IDs> | /name:<comma delimited feature names>}} [/variant:<0-63>] [/variantpayloadkind:<none | resident | external>] [/variantpayload:<0-4294967295>] [/experiment] - [/priority:<enrollment | service | user | userpolicy | test>] [/store:<both | runtime | boot>] + [/priority:{{<enrollment | service | user | userpolicy | test> | <1-14>}}] [/store:<both | runtime | boot>] The parameters in square brackets don't need to be specified and will use these defaults: Variant : 0 VariantPayloadKind: None VariantPayload : 0 Experiment : false - Priority : Service + Priority : User Store : Both Features can be specified using both their IDs and names, mixing and matching is allowed. -When an override is marked as an Experiment it becomes eligible for deletion by Windows's automatic -A/B feature delivery mechanism. Do NOT use this flag if you want overrides to persist. +Service priority overrides are managed by Windows's automated A/B feature delivery mechanism. Experiment +type overrides with this priority may get deleted without notice. Creating non-Experiment overrides with this +priority may negatively impact automated A/B feature delivery. Using the Service priority is not recommended. Writing to the Boot store is necessary for features to persist across reboots. Changes to this store become effective the next time you reboot. The Runtime store can be used to make instantenous changes, however not diff --git a/ViVeTool/UpdateCheck.cs b/ViVeTool/UpdateCheck.cs index 43a3e81..39af156 100644 --- a/ViVeTool/UpdateCheck.cs +++ b/ViVeTool/UpdateCheck.cs @@ -52,13 +52,13 @@ internal static GitHubRepoContent GetLatestDictionaryInfo() internal static bool IsDictOutdated(string sha) { - return sha != HashUTF8TextFile(FeatureNaming.DictFileName); + return sha != HashUTF8TextFile(FeatureNaming.DictFilePath); } internal static void ReplaceDict(string url) { EnsureWebClient(); - UcWebClient.DownloadFile(url, FeatureNaming.DictFileName); + UcWebClient.DownloadFile(url, FeatureNaming.DictFilePath); } private static void EnsureWebClient() diff --git a/ViVeTool/ViVeTool.csproj b/ViVeTool/ViVeTool.csproj index 3ab0265..23f6a2d 100644 --- a/ViVeTool/ViVeTool.csproj +++ b/ViVeTool/ViVeTool.csproj @@ -79,6 +79,7 @@ ResXFileCodeGenerator Resources.Designer.cs + Designer