Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 47 additions & 2 deletions SyncMLViewer/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,57 @@ namespace SyncMLViewer
{
internal static class Helper
{
// The tree root node shown by regedit.exe comes from a localized string resource in
// regedit.exe.mui, it reads "Computer" on en-US and "Ordinateur" on fr-FR for example.
// Everything below the root node (the hive names) is not localized.
private static readonly string[] RegistryHiveNames =
{
"HKEY_LOCAL_MACHINE", "HKEY_CURRENT_USER", "HKEY_CLASSES_ROOT", "HKEY_USERS",
"HKEY_CURRENT_CONFIG", "HKEY_PERFORMANCE_DATA", "HKEY_DYN_DATA",
"HKLM", "HKCU", "HKCR", "HKU", "HKCC"
};

/// <summary>
/// Removes the tree root node from a registry path so that the path becomes independent of
/// the Windows display language.
/// </summary>
/// <remarks>
/// regedit.exe matches the first segment of its LastKey value against the localized name of
/// its tree root node. A hard coded English "Computer\" therefore only resolves on an
/// English Windows, on every other display language regedit silently falls back to the root
/// node instead of navigating to the requested key. regedit happily accepts a LastKey value
/// without any root node prefix and prepends the correct localized name itself, so dropping
/// the prefix works on all languages.
/// </remarks>
internal static string NormalizeRegistryPath(string path)
{
if (string.IsNullOrWhiteSpace(path))
{
return string.Empty;
}

var normalized = path.Trim().Trim('\\');
var separatorIndex = normalized.IndexOf('\\');
var firstSegment = separatorIndex < 0 ? normalized : normalized.Substring(0, separatorIndex);

// already rooted at a hive, nothing to strip
if (RegistryHiveNames.Contains(firstSegment, StringComparer.OrdinalIgnoreCase))
{
return normalized;
}

// the first segment is the localized root node, drop it
return separatorIndex < 0 ? string.Empty : normalized.Substring(separatorIndex + 1);
}

public static void OpenRegistry(string path)
{
// CreateSubKey instead of OpenSubKey, the Regedit key does not exist yet on a profile
// where regedit.exe has never been started
using (var registryKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Applets\Regedit", true))
.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Applets\Regedit"))
{
registryKey?.SetValue("LastKey", path);
registryKey?.SetValue("LastKey", NormalizeRegistryPath(path));
}

var processes = Process.GetProcessesByName("regedit");
Expand Down
1 change: 1 addition & 0 deletions SyncMLViewer/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
<MenuItem Header="-> MDM Diagnostics _folder" InputGestureText="Ctrl+Shift+M" Click="MenuItemOpenMDMDiagnosticsFolder_Click"/>
<MenuItem Header="-> DC\HostOS folder" InputGestureText="Ctrl+Shift+D" Click="MenuItemOpenDeclaredConfigurationHostOSFolder_Click" ToolTip="Folder C:\ProgramData\microsoft\DC\HostOS is for DeclaredConfiguration .xml files"/>
<MenuItem Header="-> SystemProfile\AppData\Local\mdm folder" Click="MenuItemOpenSystemProfileMDM_Click" ToolTip="IME Agent will be installed from C:\Windows\System32\Config\SystemProfile\AppData\Local\mdm as MSI and log files are written there."/>
<MenuItem Header="-> Device Inventory Agent folder" Click="MenuItemOpenDeviceInventoryAgentFolder_Click" ToolTip="Folder C:\Program Files\Microsoft Device Inventory Agent holds the Device Inventory Agent used for Intune device inventory."/>
</MenuItem>
<Separator />
<MenuItem Header="Advanced" StaysOpenOnClick="True">
Expand Down
26 changes: 18 additions & 8 deletions SyncMLViewer/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1962,37 +1962,37 @@ private async void MenuItemCheckUpdate_OnClick(object sender, RoutedEventArgs e)

private void MenuItemRegistryEnrollments_Click(object sender, RoutedEventArgs e)
{
Helper.OpenRegistry(@"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Enrollments");
Helper.OpenRegistry(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Enrollments");
}

private void MenuItemRegistryProvisioning_Click(object sender, RoutedEventArgs e)
{
Helper.OpenRegistry(@"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Provisioning");
Helper.OpenRegistry(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Provisioning");
}

private void MenuItemRegistryPolicyManager_OnClick(object sender, RoutedEventArgs e)
{
Helper.OpenRegistry(@"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PolicyManager");
Helper.OpenRegistry(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PolicyManager");
}

private void MenuItemRegistryRebootRequiredUris_Click(object sender, RoutedEventArgs e)
{
Helper.OpenRegistry(@"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Provisioning\SyncML\RebootRequiredURIs");
Helper.OpenRegistry(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Provisioning\SyncML\RebootRequiredURIs");
}

private void MenuItemRegistryDeclaredConfiguration_Click(object sender, RoutedEventArgs e)
{
Helper.OpenRegistry(@"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DeclaredConfiguration");
Helper.OpenRegistry(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DeclaredConfiguration");
}

private void MenuItemRegistryEnterpriseDesktopAppManagement_Click(object sender, RoutedEventArgs e)
{
Helper.OpenRegistry(@"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\EnterpriseDesktopAppManagement");
Helper.OpenRegistry(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\EnterpriseDesktopAppManagement");
}

private void MenuItemRegistryIntuneManagementExtension_Click(object sender, RoutedEventArgs e)
{
Helper.OpenRegistry(@"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\IntuneManagementExtension");
Helper.OpenRegistry(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\IntuneManagementExtension");
}

private async void MenuItemMdmDiagnostics_OnClick(object sender, RoutedEventArgs e)
Expand Down Expand Up @@ -2351,6 +2351,16 @@ private void MenuItemOpenDeclaredConfigurationHostOSFolder_Click(object sender,
Helper.OpenFolder(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), @"Microsoft\DC\HostOS"));
}

private void MenuItemOpenDeviceInventoryAgentFolder_Click(object sender, RoutedEventArgs e)
{
// ProgramW6432 always points to the native Program Files, SpecialFolder.ProgramFiles
// would resolve to Program Files (x86) when running as a 32-bit process
var programFiles = Environment.GetEnvironmentVariable("ProgramW6432")
?? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);

Helper.OpenFolder(Path.Combine(programFiles, "Microsoft Device Inventory Agent"));
}

private void MenuItemClearHistoryItems_Click(object sender, RoutedEventArgs e)
{
resultStack.Children.Clear();
Expand Down Expand Up @@ -2732,7 +2742,7 @@ private void MenuItemLookupNodeCache_Click(object sender, RoutedEventArgs e)

if (int.TryParse(text, out _))
{
Helper.OpenRegistry($@"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Provisioning\NodeCache\CSP\Device\MS DM Server\Nodes\{text}");
Helper.OpenRegistry($@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Provisioning\NodeCache\CSP\Device\MS DM Server\Nodes\{text}");
}
}

Expand Down