3
votes

I'm looking for a script which can find a registry key and delete it. My key is like : "{24EAA2C1-3EE7-40E0-AEA3-D20AA14A6005}". THis key is stored in many places:

HKEY_CLASSES_ROOT\CLSID\{MY_KEY}
HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{MY_KEY}
HKEY_CURRENT_USER\Software\Classes\CLSID\{MY_KEY}
HKEY_CURRENT_USER\Software\Classes\Wow6432Node\CLSID\{MY_KEY}
HKEY_USERS\S-1-5-21-1786904987-2011555162-1551513139-1001\Software\Classes\CLSID\{MY_KEY}
HKEY_USERS\S-1-5-21-1786904987-2011555162-1551513139-1001\Software\Classes\Wow6432Node\CLSID\{KEY}
HKEY_USERS\S-1-5-21-1786904987-2011555162-1551513139-1001_Classes\CLSID\{MY_KEY}
HKEY_USERS\S-1-5-21-1786904987-2011555162-1551513139-1001_Classes\Wow6432Node\CLSID\{MY_KEY}

But these locations may vary (that's the reason why I have to find them before to delete them). I would like to remove each occurances of this key using a C# script (in a console application)

I tried this:

static void Main(string[] args)
{
    DeleteKeyTest("{MY_KEY}");
}

private RegistryKey baseRegistryKey = Registry.ClassesRoot;
public void DeleteKeyTest(string KeyName)
{
    try
    {
        RegistryKey rk = baseRegistryKey;
        rk.DeleteSubKey(KeyName);       
    }
    catch (Exception e)
    {
    }
}

I get an error:

Can not delete a subkey, because it does not exist.

EDIT

Here is my code which is used to find all the occurances of the key:

public List<string> SearchKey(string Key)
{
    List<string> ListKeys = getKeyPath(Key, RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64));
    ListKeys.AddRange(getKeyPath(Key, RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64)));
    ListKeys.AddRange(getKeyPath(Key, RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)));
    ListKeys.AddRange(getKeyPath(Key, RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Registry64)));
    ListKeys.AddRange(getKeyPath(Key, RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, RegistryView.Registry64)));
    return ListKeys;
}

private List<string> getKeyPath(string key, RegistryKey registryKey)
{
    List<string> keys = new List<string>();
    if (CanReadRegistryKey(registryKey))
    {
        foreach (string keyname in registryKey.GetSubKeyNames())
        {
            if (keyname.Contains(key))
                keys.Add(registryKey.Name + "\\" + keyname);

            if (CanReadKey(registryKey, keyname))
                keys.AddRange(getKeyPath(key, registryKey.OpenSubKey(keyname, RegistryKeyPermissionCheck.ReadSubTree)));
        }
    }
    return keys;
}

private bool CanReadRegistryKey(RegistryKey registryKey)
{
    try
    {
        registryKey.GetSubKeyNames();
        return true;
    }
    catch (UnauthorizedAccessException e)
    {
        return false;
    }
}

private bool CanReadKey(RegistryKey registryKey, string keyname)
{
    try
    {
        registryKey.OpenSubKey(keyname, RegistryKeyPermissionCheck.ReadSubTree);
        return true;
    }
    catch (SecurityException e)
    {
        return false;
    }
}

Usage :

List<string> ListKeys = SearchKey("MY_KEY");

I do not always get the same result. Sometimes I get 7 keys found, sometimes 8. (The missing key is HKEY_CLASSES_ROOT\Wow6432Node\CLSID{MY_KEY})

Here is my code for deleting:

public int RemoveKey(string Key)
{
    int count = RemoveKeys(Key, RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64));
    count += RemoveKeys(Key, RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64));
    count += RemoveKeys(Key, RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64));
    count += RemoveKeys(Key, RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Registry64));
    count += RemoveKeys(Key, RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, RegistryView.Registry64));
    return count;
}

private int RemoveKeys(string key, RegistryKey registryKey)
{
    int count = 0;
    if (CanReadRegistryKey(registryKey))
    {
        foreach (string keyname in registryKey.GetSubKeyNames())
        {
            count += RemoveKeys(key, registryKey.OpenSubKey(keyname));
            try
            {
                if (keyname.Contains(key))
                {
                    registryKey.DeleteValue(keyname);
                    count++;
                }
            }
            catch (Exception e)
            {
            }
        }
    }
    return count;
}

Usage :

int NumberOfRemovedKeys = RemoveKey("MY_KEY");

But I allway got an error on this code:

registryKey.DeleteValue(keyname);

Error message :

System.UnauthorizedAccessException: Can not write to the registry key.

I got the same error when I try to launch the application in admin mode. But when I try to remove manualy the key from regedit, there is no problem.

In the "search" code, I got a list of key, with the full path. I've tried to remove the key directly using the full path but it's not possible because RegistryKey has to be initialized using RegistryHive (for exemple RegistryHive.ClassesRoot), but the RegistryHive is allready in the full path.

How can I get the authorization to remove ?

2

2 Answers

0
votes

You have a complete example Read, write and delete from registry with C#

And MSDN Doc

It's a good start, hope it helps!

0
votes

By default, on a 64-bit Windows operating system 32-bit applications access 32-bit registry keys, and 64-bit applications access 64-bit registry keys.

For example, the 64-bit key:

HKEY_LOCAL_MACHINE\Software\NVIDIA Corporation

And the 32-bit key:

HKEY_LOCAL_MACHINE\Software\WOW6432Node\NVIDIA Corporation

Do not have the same content.

So, if on a 64-bit OS you open HKEY_LOCAL_MACHINE\Software\NVIDIA Corporation from a 32-bit application you will get automatic redirection to HKEY_LOCAL_MACHINE\Software\WOW6432Node\NVIDIA Corporation unless you specify which registry view you want when you open the key.

What that means in practice is that for HKEY_LOCAL_MACHINE\Software and for HKEY_CLASSES_ROOT you have to open and search both 64-bit and 32-bit registry view.

As for why sometimes you see a key and sometimes you don't most likely explanation is that you are not running the application in interactive user context:

When you call these functions from a process running in the interactive user account, the system merges the default settings in HKEY_LOCAL_MACHINE\Software\Classes with the interactive user's settings at HKEY_CURRENT_USER\Software\Classes. For more information on how these settings are merged, see Merged View of HKEY_CLASSES_ROOT.

For anything else please consult full documentation for HKEY_CLASSES_ROOT key.